TS4.7+更新
大家好! TypeScript 4.7将引入microsoft/TypeScript#47607中实现的实例化表达式,这将允许您直接指定泛型函数的类型参数,而无需实际调用该函数,因此不再需要像答案中所示那样滥用类。以下是示例:
type GFooT<T,> = typeof foo<T> // (arg: T) => T
type GFooParametersT<T,> = Parameters<typeof foo<T>> // [arg: T]
type GFooReturnT<T,> = ReturnType<typeof foo<T>> // T
这几乎与问题中的语法相同,只是在类型参数后不支持尾随逗号(但在类型参数声明后支持)。太好了!
代码游乐场链接
在TypeScript中有两种不同类型的泛型:泛型函数和泛型类型...看起来你想让编译器为你将一个转换成另一个,这是不直接支持的。请参考上一个TS4.6的答案。
明确一点:
通用的类型具有需要在使用特定类型之前指定的类型参数。例如:
type GenType<T> = (x: T) => T[];
declare const oops: GenType; // error
declare const genT: GenType<string>; // okay
const strArr = genT("hello"); // string[];
const numArr = genT(123); // error!
在这里,{{GenType}}是一种通用类型。您需要指定类型参数以将其用作值的类型,然后生成的类型不再是通用的。{{genT}}函数接受一个字符串并返回一个字符串数组。它不能用作接受数字并返回数字数组的函数。
另一方面,通用{{函数}}具有特定类型,可以像任何可能的类型参数替换一样起作用。当您使用它时,通用函数类型的值仍然是通用的。类型参数附加到调用签名:
type GenFunc = <T>(x: T) => T[];
declare const genF: GenFunc;
const strArr = genF("hello");
const numArr = genF(123);
在这里,GenFunc
是指通用函数的特定类型。当调用genF
函数时,它仍然是通用的。
通用函数(包括通用构造函数)可以被视为通用值,而不是通用类型。
这两种泛型类型是相关的,但TypeScript类型系统不足以描述它们之间的关系。在其他一些语言中,您可能能够定义一个泛型类型来涵盖另一个类型,例如:
type GenFunc = forall T, GenType<T>
或者
type GenType<T> = instantiate GenFunc with T
但在TypeScript中是不可能的。也许如果我们得到
microsoft/TypeScript#1213中请求的更高级类型,但现在还没有。因此,在类型系统中不能直接将
GenFunc
转换为
GenType
。
有一些邪恶可怕的方法可以强制编译器根据GenFunc
计算GenType
。我知道的方法利用了泛型类属性初始化和在TypeScript 3.4中引入的一些用于泛型函数的高阶类型推断。我让编译器认为我正在计算值,而实际上我没有任何值,然后获取其中一个假值的类型:
class GenTypeMaker<T> {
getGenType!: <A extends any[], R>(cb: (...a: A) => R) => () => (...a: A) => R;
genType = this.getGenType(null! as GenFunc)<T>()
}
type GenType2<T> = GenTypeMaker<T>['genType']
// type GenType2<T> = (x: T) => T[]
你可以验证
GenType2<T>
与
GenType<T>
是相同的类型,如果你将
GenFunc
更改为任何具有一个类型参数的泛型函数,则
GenType2<T>
也会相应更改。
但我不知道我是否想要推荐任何人实际使用这种方法。它并不能真正地扩展或组合;如果你有一个对象,其中包含一个类型参数的通用函数,并且你想将其转换为一个对象,其中包含指定类型参数的具体函数,那么没有办法在不为每个对象属性执行一次的情况下从类型系统中获取它。
代码的游乐场链接