【发布时间】:2021-12-20 20:38:16
【问题描述】:
我很困惑利用 type predicates (user-defined type guard functions)
正如我在之前的问题中所述:How to fix the broken code with idempotent (self flatten) types in TypeScript?,我的最终目标是实现一个可映射对象,该对象具有 map 方法(示例代码中的mp 以避免混淆)应该与管道操作符类似地工作(例如作为 F#|>)。
由于 JavaScript 中的任何对象和原语都是幂等的(self/auto flatten),Object(5) === Object(Object(5));我首先尝试将幂等对象/函子实现为P 和mp。
我问How to express idempotent (self flatten) types in 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 type predicates (user-defined type guard functions)
(请注意:这是最简单的代码来解决这个问题;实际实现应该使用Symbol 属性来检查自我类型is 而不是使用mp 属性,还需要None)
在实现内部工作正常,但在测试代码中不起作用
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>
有什么想法吗?我已经为此工作了一个多星期。谢谢!
【问题讨论】:
-
好吧,至少对于这个问题,我想通了……这种类型推断只在定义的上下文中可用,对于上下文外部对输入类型的反应,我们需要写条件类型
:A extends {mp: unknown} ? A : P<A>等...
标签: javascript typescript functional-programming