typescript - 柯里化(Currying)函数的返回类型

标签 typescript generics types currying

使用ReturnType<T>正如您所期望的,函数中返回返回类型。

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

此外,正如您所期望的,当使用柯里化(Currying)函数时,返回类型为

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

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

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

最佳答案

这目前有效(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 团队不确定他们是否想要支持/鼓励这一点。

关于typescript - 柯里化(Currying)函数的返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59548176/

相关文章:

java - 如何向 mosby MVPActivity 添加基类?

types - F#:组织类型和模块的最佳实践

typescript - 使用 `import type` 语句修复循环依赖引用错误

typescript :从数组类型中检索元素类型信息

java - 在父类(super class)方法中返回通用父类(super class)的子类

javascript - 如何访问环回模型属性类型? (模型.定义.属性.类型)

c# - 可以从 ASP .net 访问哪些 C# 类型?

typescript - 为什么 makeStyles 和 createStyles 必须分开(Material UI + TypeScript)?

javascript - 如何使用 Protractor 在 Monaco Editor 中插入代码?

java - 使用库泛型类而不使用其泛型功能会使其成为原始类型吗?