繁体   English   中英

TypeScript `is` 类型谓词(用户定义的类型保护函数)来实现幂等对象类型

[英]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)) ; 我首先尝试将幂等对象/函子实现为Pmp

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

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