为什么在 TypeScript 中类型别名不能与泛型函数一起使用? 例如,这里 TS 没有将 Identical 类型定义为泛型。
type Identical = <T>(v: T) => T;
const identical: Identical<string> = (v) => v
我知道正确的变体是:
type Identical<T> = (v: T) => T;
但是为什么第一个示例不起作用以及什么类型的
T
?
在下文中,我将使用“特定”一词来表示“非通用”。 通常人们会说“具体”,但我担心有人会认为这意味着“不是
abstract
”,而这与abstract
类无关。
除了泛型函数之外,TypeScript 只有泛型类型,没有泛型值。 对于泛型类型,类型参数写在类型名称后面的尖括号中:
type GenericType<T> = {x: T};
您可以拥有像
Foo<T>
这样的泛型类型,但该类型的任何实际 value 都必须是特定的,实际特定类型指定为 T
:
declare const badValue1: GenericType; // error, requires 1 type argument
declare const badValue2: GenericType<T>; // error, cannot find name 'T'
declare const goodValue: GenericType<string>; // okay
请注意,
GenericType<string>
现在是特定类型,相当于{x: string}
。 因此,一旦您通过插入特定类型在泛型类型中指定泛型参数,您就会得到特定类型。
泛型函数不同:泛型函数类型的值是泛型的。 它充当不同特定功能类型的完整系列。 对于泛型函数类型,类型参数写在函数参数列表之前的尖括号中:
type GenericFunction = <T>(x: T, y: T) => void;
泛型函数的类型本身不一定是泛型的;上面的
GenericFunction
名称没有类型参数。 所以你不能通过添加来指定泛型类型参数只有在call函数时才指定泛型函数类型参数:
declare const badFunc: GenericFunction<string>; // error, GenericFunction is not generic
declare const goodFunc: GenericFunction; // okay
const ret = goodFunc<string>("okay", "fine"); // okay, type parameter specified as string
const ret2 = goodFunc("okay", "fine"); // also okay, type parameter inferred as string
那么,它们之间的区别:
type IdGenericType<T> = (x: T) => T;
type IdGenericFunc = <T>(x: T) => T;
第一个是generic类型,指定时将引用specific函数,而第二个是specific类型,它引用generic函数。 这些类型虽然相关,但并不等同。 您可以将
IdGenericFunc
类型的值分配给您想要的任何特定类型 IdGenericType<XXX>
类型的任何变量 XXX
:
let id: IdGenericFunc = x => x;
let idString: IdGenericType<string> = id; // okay
但反之则不然:
const otherId: IdGenericFunc = idString; // error! T not assignable to string
这是有道理的,因为
IdGenericType<string>
只知道接受和输出 string
:
idString = x => x + "!"; // okay
所以你不能假设
IdGenericType<string>
是有效的 IdGenericFunc
。 IdGenericType<T>
和IdGenericFunc
之间的关系是,IdGenericFunc
本质上是IdGenericType<T>
的交集对于所有可能的
T
:
// type IdGenericFunc = forall T. IdGenericType<T>; // invalid syntax
但是无法直接用 TypeScript 来表达(我借用了
Haskell的
forall
语法)。
请参阅有关泛型值的 TypeScript GitHub 问题,microsoft/TypeScript#17574 了解更多信息。