Typescript中Unpacked <t>的递归版本?

时间:2018-07-23 13:52:53

标签: typescript

引用https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html中的Unpacked

type Unpacked<T> =
    T extends (infer U)[] ? U :
    T extends (...args: any[]) => infer U ? U :
    T extends Promise<infer U> ? U :
    T;

可以有一个递归版本吗? 我已经尝试过,并且正在循环引用自身错误。

type Unpacked<T> =
    T extends (infer U)[] ? Unpacked<U> :
    T extends (...args: any[]) => infer U ? Unpacked<U> :
    T extends Promise<infer U> ? Unpacked<U> :
    T;

以上代码由于循环引用而失败。

递归版本将执行此操作:

Unpacked<Array<Promise<number[]>>> === number;

当我们不知道它需要打开多深时,它很有用。

1 个答案:

答案 0 :(得分:4)

很遗憾,根据您的定义,除非在特定情况下,conditional types不允许递归引用自己。在上述链接请求请求的描述中,介绍了该功能:

  

类似于联合和相交类型,不允许条件类型递归地引用它们自己(但是,如上面的DeepReadonly<T>示例所示,允许通过接口类型或对象文字类型的间接引用)。例如,以下是错误:

     

type ElementType<T> = T extends any[] ? ElementType<T[number]> : T; // Error

有些时候,人们已经设法愚弄了编译器以允许像这样的递归类型,但是在某些情况下,有些人可能会编写使编译器崩溃的东西。它是正式的a bad idea,因此我不会尝试告诉您如何使用该方法。

我也希望看到一个解决方案,但是现在还不存在(无论如何从TS3.0开始)。


因此,解决方法。最直接的解决方法是找出您可能需要的实际最大深度,然后为此编写代码。这是一种实现方法:

type _U<T> =
  T extends (infer U)[] ? U :
  T extends (...args: any[]) => infer U ? U :
  T extends Promise<infer U> ? U :
  T;

// up to 8 levels deep
type Unpacked<T> = _U<_U<_U<_U<_U<_U<_U<_U<T>>>>>>>>

您可以验证它是否适用于您的示例:

type JustNumber = Unpacked<Array<Promise<number[]>>>; // number

这不是完美的,但它可能是目前为止最好的。希望能有所帮助。祝你好运!