【问题标题】:ReturnType of curried function柯里化函数的 ReturnType
【发布时间】:2020-04-24 03:30:57
【问题描述】:

在函数中使用ReturnType<T> 会如您所愿返回返回类型。

type F = () => string
//ReturnType<F> === string

此外,正如您所期望的,当使用 curried 函数时,返回类型是

type FF = () => () => string
//ReturnType<FF> === () => string

有没有办法创建一个返回最终返回的泛型类型?即

type FF = () => () => string
//FinalReturnType<FF> === string

【问题讨论】:

    标签: typescript generics types currying


    【解决方案1】:

    这目前有效(TS 3.7),但 TS 团队并没有故意允许它,也没有决定支持它。它可能会在未来的版本中中断。

    type FinalReturnType<T> = {
      0: T,
      1: T extends (...args: any) => infer R ? FinalReturnType<R> : T,
    }[T extends (...args: any) => infer _ ? 1 : 0];
    

    它必须如此奇怪和丑陋,因为目前有一个限制,即一个类型只能在嵌套在另一个结构类型(在这种情况下,一个具有两个键的对象)中时才能调用自身,但随后我们立即拉取该属性我们需要元组。

    理想的外观:

    如果语言支持这种机制,我认为它会很简单:

    type FinalReturnType<T> = T extends (...args: any) => infer R
                                  ? FinalReturnType<R> 
                                  : T;
    

    换句话说,使用递归定义。如果T 是一个函数,它会调用自己并传递函数的返回类型。如果不是函数,则返回 T 本身。比如:

    FinalReturnType<string> // -> string
    

    这样就终止了递归:当你解开所有返回函数的函数层时,你最终会到达一个非函数。

    很遗憾,这是不可能的,会产生错误:

    Type alias 'FinalReturnType' circularly references itself.
    

    有一个change to enable recursive type references,但它不支持这种情况。

    an open discussion of more general support for recursion

    目前的情况是,只有在自调用周围加上[]使其成为元组,才能编译我的答案:

    type FinalReturnType<T> = T extends (...args: any) => infer R
                                    ? [FinalReturnType<R>] 
        : T;
    
    type t1 = FinalReturnType<string>;  // -> string
    
    type F = () => string
    type t2 = FinalReturnType<F>;       // -> [string]
    
    type FF = () => () => string
    type t3 = FinalReturnType<FF>;      // -> [[string]]
    

    如您所见,这将结果重新包装在嵌套元组的层中,您又回到了同样的问题,因为您也无法解开这些。

    目前,您目前可以使用包装在具有两个属性的对象中的技巧,然后通过索引正确的属性立即展开,如本答案顶部所述。但这是偶然启用的,TS 团队不确定他们是否愿意支持/鼓励这一点。

    【讨论】:

    • 讨论描述了解决方法并警告它是not supported。对于任何需要继续工作的生产代码,我会避免推荐这个。相反,我通常会写一个丑陋的类型,专门只支持一些固定的递归深度,比如说 5。(在这种情况下,你会有type FinalReturnType&lt;T&gt; = ...FRT0&lt;T&gt;...type FRT0&lt;T&gt; = ...FRT1&lt;T&gt;...,一直到type FRT5&lt;T&gt; = ....,最后一个一个只是保释。)我希望支持递归条件类型,但事实并非如此。
    • @jcalz 感谢您的澄清,添加了突出的免责声明。
    • 看起来对递归类型的官方支持即将推出:github.com/microsoft/TypeScript/pull/40002
    猜你喜欢
    • 2016-01-01
    • 2021-02-07
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多