[英]How to fix the broken code with idempotent (self flatten) types in TypeScript?
这是一个与我之前的问题直接相关的问题
我的目的是实现一个对象,该对象将 JavaScript 值包装为具有map(f)
方法。
下面是简化的代码,第一个工作没有错误。
现在,在第二个代码中,我创建了具有 idempotence 类型的P
对象。
应该是(可能)
P<P<unknown>> == P<unknown>
type p<A> = {
map: <B>(R: (a: A) => B) => P<B>
};
type P<A> = //-------------idempotence
A extends p<unknown>
? A
: p<A>;
该代码按预期工作:
const x = P(5); // p<number>
const xx = P(P(5)); // p<number>
; 然而,相反,出现了一个新错误:
我自己调查了很长时间,但不知道这是怎么发生的,最重要的是如何解决这个问题。
任何的想法? 一如既往的感谢!
另请参阅TypeScript 游乐场
最简单的没有错误的版本
type pp<A> = {
map: <B>(R: (a: A) => B) => pp<B>
};
const P = <A,>(x: A) =>
Object.defineProperty(Object(x),
"map",
{
enumerable: false,
configurable: true,
value: <B,>(f: (a: A) => B) => P(f(x))
}) as pp<A>;
const x = P(5); // pp<number>
const xx = P(P(5)); // pp<pp<number>>
const compose =
<A, B, C>(g: (b: B) => C) =>
(f: (a: A) => B) =>
(a: A) =>// g(f(a))
P(a).map(f).map(g);
// no error
具有类型错误的幂等版本
type p<A> = {
map: <B>(R: (a: A) => B) => P<B>
};
type P<A> = //-------------idempotence
A extends p<unknown>
? A
: p<A>;
const P = <A,>(x: A) =>
Object.defineProperty(Object(x),
"map",
{
enumerable: false,
configurable: true,
value: <B,>(f: (a: A) => B) => P(f(x))
}) as P<A>;
const x = P(5); // p<number>
const xx = P(P(5)); // p<number>
const compose =
<A, B, C>(g: (b: B) => C) =>
(f: (a: A) => B) =>
(a: A) =>// g(f(a))
P(a).map(f).map(g); // f is type-error ts(2345)
/* Argument of type '(a: A) => B' is not assignable to parameter of type '((a: unknown) => B) & ((a: A) => B)'.
Type '(a: A) => B' is not assignable to type '(a: unknown) => B'.
Types of parameters 'a' and 'a' are incompatible.
Type 'unknown' is not assignable to type 'A'.
'A' could be instantiated with an arbitrary type which could be unrelated to 'unknown'.ts(2345)
(parameter) f: (a: A) => B */
当 TypeScript 必须使用泛型时,它似乎无法解决“幂等类型”的问题。 当查看P<A>
(其中A
是来自compose
的类型参数)时,TypeScript 不知道A extends p<A>
是否A extends p<A>
,因此它(理所当然地)必须假设它可能是。 compose
内部的P(a)
调用的返回类型为P<A>
,TypeScript 正确地将其解析为p<unknown> | p<A>
p<unknown> | p<A>
- 它有一个参数类型为((a: unknown) => B) & ((a: A) => B)
的map
方法,与f
不兼容。
也就是说,你的P
函数也被破坏了,并不是真正的幂等:
map
回调。 P([1, 2]).map(arr => arr.map(x=>x+1))
确实可以编译并且应该合法地返回P([2, 3])
,但实际上结果是字符串"1,21"
运行时为"1,21"
。 去搞清楚。P(P(5))
(您的xx
示例)声称使用数字调用map
回调,但实际上使用Number
实例调用它。 如果您尝试实现Identity
函子,只需使其返回一个新对象,而不要尝试从中创建“幂等类型”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.