typescript - 递归函数的类型

标签 typescript recursion monads

我正在尝试为一个类编写一个 unwrap 方法,该类包含一个值,或者一个具有内部值的实例:

class Identity<T> {
  private readonly value: T;

  constructor(value: T) {
    this.value = value;
  }

  static of<T>(value: T): Identity<T> {
    return new Identity(value);
  }

  join(): T { // which return type should go here?
    if (this.value instanceof Identity) {
      return this.value.join();
    }

    return this.value;
  }
}

这是测试:

const one = Identity.of(Identity.of(Identity.of(123)));
const result: number = one.join();
expect(result).toEqual(123);

谢谢大家!!

最佳答案

您可以更改类型参数 T , 所以它总是完全嵌套的类型:

class Identity<T> {
  private readonly value: T | Identity<T>;

  constructor(value: Identity<T>);
  constructor(value: T);

  constructor(value: any) {
    this.value = value;
  }

  static of<T>(value: Identity<T>): Identity<T>;
  static of<T>(valud: T): Identity<T>;
  static of<T>(value: T | Identity<T>) {
    return new Identity(value);
  }

  join(): T {
    if (this.value instanceof Identity) {
      return this.value.join();
    }
    return this.value;
  }
}

const one = Identity.of(Identity.of(Identity.of(123)));
const result: number = one.join();

const result2 = new Identity(new Identity(new Identity(321)));
// Identity<number>

我建议使用上述方法,因为它似乎提供了您真正想要的功能。

如果你需要类型T实际上是一个嵌套的 Identity<Identity<...>>仍然有可能,如果 value是公开的,我们可以执行以下操作:

class Identity<T> {
  public readonly value: T;

  constructor(value: T) {
    this.value = value;
  }

  static of<T>(value: T): Identity<T> {
    return new Identity(value);
  }

  public join(): IdentityJoinResult<T> {
    if (this.value instanceof Identity) {
      return this.value.join();
    }

    return this.value as IdentityJoinResult<T>;
  }
}

type IdentityJoinResult<T> = 
  T extends Identity<any>
    ? { [Key in keyof T]: IdentityJoinResult<T[Key]> }["value"]
    : T
;

const one = Identity.of(Identity.of(Identity.of(123)));
const result: number = one.join();

const result2 = new Identity(new Identity(new Identity(321))).join();

但是如果你改变value要私有(private)化,您会注意到您不再能够通过类型签名中的“值”进行索引,因此我们解决这个问题的最后一件事是将我们的类型逻辑推迟到一个单独的公共(public)接口(interface),我们可以从输入:

class Identity<T> {
  private readonly value: T;

  constructor(value: T) {
    this.value = value;
  }

  static of<T>(value: T): Identity<T> {
    return new Identity(value);
  }

  public join(): IdentityJoinResult<T> {
    if (this.value instanceof Identity) {
      return this.value.join();
    }

    return this.value as IdentityJoinResult<T>;
  }
}

interface NestedIdentity<T> {
  _value: T extends Identity<infer U> ? NestedIdentity<U> : T;
}

type NestedIdentityValue<T> = 
  T extends NestedIdentity<any>
    ? { [Key in keyof T]: NestedIdentityValue<T[Key]> }["_value"]
    : T
;

type IdentityJoinResult<T> = NestedIdentityValue<NestedIdentity<T>>;

const one = Identity.of(Identity.of(Identity.of(123)));
const result: number = one.join();
const result2 = new Identity(new Identity(new Identity(321))).join();

关于typescript - 递归函数的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58563611/

相关文章:

haskell - 如何在 Haskell 函数中将随机数用作 Double ?

gruntjs - 防止 grunt-ts 生成多个 .map 和 .js 文件

typescript - typescript 中不一致类型的数组

c - Unload() 递归 C Segfault(类似 TRIE 的数据库) CS50 pset5

Scala 案例类和尾递归最佳实践

haskell - 为什么 Control.Monad.Morph.hoist 有 Monad 约束?

java - Java 8 是否缺少 OptionalBoolean?

typescript - 如果输入参数绝对不是未定义,则约束输出不是未定义

加载动态组件时 Angular 4 AOT 编译错误 : Runtime compiler is not loaded

java - 递归地将新节点添加到 LinkedList 的末尾?