![](/img/trans.png)
[英]Typescript: type guard for whether an object property is defined, when the key is a wide type?
[英]TypeScript `is` type predicates (user-defined type guard functions) to implement idempotent object types
我很困惑利用类型谓词(用户定义的类型保护函数)
正如我之前提出的问题: 如何在 TypeScript 中使用幂等(自展平)类型修复损坏的代码? ,我的最终目标是实现一个具有映射方法(示例代码中的mp
以避免混淆)的可映射对象,该方法应该与管道运算符(例如 F# |>
)类似。
由于 JavaScript 中的任何对象和原语都是幂等的(self/auto flatten),因此Object(5) === Object(Object(5))
; 我首先尝试将幂等对象/函子实现为P
和mp
。
我问如何在 TypeScript 中表达幂等(自展平)类型? ; : TTX = TX ; 然而,不幸的是,答案中的方法失败了:
这种方法最终失败了
type p<A> = {
map: <B>(R: (a: A) => B) => P<B>
};
type P<A> = //-------------idempotence
A extends p<unknown>
? A
: p<A>;
我现在放弃了这种方法,并重构了我的代码以紧密绑定 JS 和 TypeScript 推理,并尝试利用is
类型谓词(用户定义的类型保护函数)
(请注意:这是在这个问题上亲缘最简单的代码;实际执行应使用Symbol
的属性来检查自我型is
,而不是使用mp
特性,也None
必要)
另见: TS游乐场
在实现内部工作正常,但在测试代码中不起作用
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) */
通过禁用没有错误版本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>
有任何想法吗? 我已经为此工作了一个多星期。 谢谢!
好吧,至少对于这个问题,我想通了......
这种类型推断只能在定义的上下文中使用,而要让上下文外部对输入类型做出反应,我们需要编写条件类型:
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.