繁体   English   中英

如何在 TypeScript 中使用幂等(自展平)类型修复损坏的代码?

[英]How to fix the broken code with idempotent (self flatten) types in TypeScript?

这是一个与我之前的问题直接相关的问题

如何在 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM