[英]TypeScript `is` type predicates (user-defined type guard functions) to implement idempotent object types
I am confused to take advantage of type predicates (user-defined type guard functions)我很困惑利用类型谓词(用户定义的类型保护函数)
As addressed in my earlier questions: How to fix the broken code with idempotent (self flatten) types in TypeScript?正如我之前提出的问题: 如何在 TypeScript 中使用幂等(自展平)类型修复损坏的代码? , my final goal is to implement a mappable object that has the map method( mp
in the sample code to avoid confusion) that should work similarly as pipeline-operator (such as F# |>
). ,我的最终目标是实现一个具有映射方法(示例代码中的mp
以避免混淆)的可映射对象,该方法应该与管道运算符(例如 F# |>
)类似。
Since any objects and primitives in JavaScript are idempotent(self/auto flatten), Object(5) === Object(Object(5))
;由于 JavaScript 中的任何对象和原语都是幂等的(self/auto flatten),因此Object(5) === Object(Object(5))
; I try to implement idempotent object/ functor as P
and mp
at first.我首先尝试将幂等对象/函子实现为P
和mp
。
I asked How to express idempotent (self flatten) types in TypeScript?我问如何在 TypeScript 中表达幂等(自展平)类型? ; ; : TTX = TX ; : TTX = TX ; however, the approach in the answer, unfortunately failed:然而,不幸的是,答案中的方法失败了:
the approach eventually failed这种方法最终失败了
type p<A> = {
map: <B>(R: (a: A) => B) => P<B>
};
type P<A> = //-------------idempotence
A extends p<unknown>
? A
: p<A>;
I gave up this approach and now, and refactored my code to bind JS and TypeScript inference closely, and try to take advantage of is
type predicates (user-defined type guard functions)我现在放弃了这种方法,并重构了我的代码以紧密绑定 JS 和 TypeScript 推理,并尝试利用is
类型谓词(用户定义的类型保护函数)
(Please note: This is the simplest code to fucus on the issue; the actual implementation should use Symbol
for property to check self-type is
instead of using mp
property, also None
needed ) (请注意:这是在这个问题上亲缘最简单的代码;实际执行应使用Symbol
的属性来检查自我型is
,而不是使用mp
特性,也None
必要)
Alse see: TS playground另见: TS游乐场
Works fine inside of the implementation, but does not work in the test code在实现内部工作正常,但在测试代码中不起作用
type P<A> = { mp: <B>(R: (a: A) => B) => P<B> };
const isP = <A,>(X: A | P<A>): X is A =>
"mp" in X;
//is type predicates (user-defined type guard functions)
const P = <A,>(x: A) =>
((X: A | P<A>) =>
isP(X)
? X // X: A //works fine as expected by isP
: Object.defineProperty(X, //X: P<A> //works fine as expected
"mp", { value: <B,>(f: (a: A) => B) => P(f(x)) })
)(Object(x)); //idempotent
//--------------------------------
const f = (a: number) => a + 1;
//--------------------------------
const x = P(5); // 5 | P<5>
// P<5> expected or P<number> is ok
const xx = P(P(5)); // 5 | P<5> | P<5 | P<5>>
// P<5> expected or P<number> is ok
const a = P(5).mp(f); //any
/* Property 'mp' does not exist on type '5 | P<5>'.
Property 'mp' does not exist on type '5'.ts(2339) */
No error version by disabling is
通过禁用没有错误版本is
type P<A> = { mp: <B>(R: (a: A) => B) => P<B> };
const isP = <A,>(X: A | P<A>): X is A =>
"mp" in X;
const P = <A,>(x: A) =>
((X: A | P<A>) =>
isP(X)
? X as unknown as P<A>
//disabling isP by overriding as P<A>
: Object.defineProperty(X,
"mp", { value: <B,>(f: (a: A) => B) => P(f(x)) })
)(Object(x));
//--------------------------------
const f = (a: number) => a + 1;
//--------------------------------
const x = P(5); // P<number>
const xx = P(P(5)); // P<P<number>>
// want this as P<number> as idempotence
const a = P(5).mp(f);// P<number>
Any ideas?有任何想法吗? I've been working on this more than a week.我已经为此工作了一个多星期。 Thanks!谢谢!
Ok, at least for this issue, I figured out...好吧,至少对于这个问题,我想通了......
The type inference of this kind is only available in the context of the definition, and for the outside of the context to react the input type, we need to write the conditional type:这种类型推断只能在定义的上下文中使用,而要让上下文外部对输入类型做出反应,我们需要编写条件类型:
type P<A> = {
mp: <B>(R: (a: A) => B) => P<B>
};
const P = <A>(x: A) =>
((X: object) =>
("mp" in X
? X
: Object.defineProperty(X,
"mp", { value: <B>(f: (a: A) => B) => P(f(x)) })
) as (A extends { mp: unknown } ? A : P<A>)
)(Object(x));
//--------------------------------
const f = (a: number) => a + 1;
//--------------------------------
const x = P(5); // P<number>
const xx = P(P(5)); // P<number>
const a = P(5).mp(f);// P<number>
//this still has problem with type-error
const compose =
<A, B, C>(g: (b: B) => C) =>
(f: (a: A) => B) =>
(a: A) =>// g(f(a))
P(a).mp(f).mp(g);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.