在 TypeScript(简称 TS)中,泛型(Generics)是一种允许你为组件(如类、接口和函数)定义灵活、可重用的类型的方式。泛型可以看作是一种类型参数化,允许你在声明时定义一个或多个类型占位符,并在使用组件时提供具体的类型。
以下是泛型在 TypeScript 中的一些主要应用:
(1)泛型函数
泛型函数可以在函数名后面使用尖括号 <>
来定义类型变量。
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString"); // 输出 "myString"
let numOutput = identity<number>(123); // 输出 123
注意,在 TypeScript 中,如果你能提供足够的类型信息,编译器通常会推断出类型参数,因此你可以省略类型参数:
let output = identity("myString"); // 输出 "myString",编译器推断出 T 是 string
(2)泛型类
泛型类允许你在类声明中定义类型变量。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
但通常,对于类中的方法,我们会使用接口和类型别名来实现泛型方法,而不是直接在类上定义泛型。
(3)泛型接口
泛型接口允许你在接口中定义类型变量。
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
(4)泛型约束
在定义泛型时,你可能会想对类型参数进行一些约束。例如,你可能希望泛型类型参数是一个具有 .length
属性的类型。这可以通过 extends
关键字来实现:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们可以访问 arg.length 了
return arg;
}
(5)泛型数组
TypeScript 提供了内置的泛型,如 Array<T>
。
let list: Array<number> = [1, 2, 3];
(6)泛型元组
在 TypeScript 4.0 及更高版本中,你可以使用泛型来创建元组:
type Pair<T, U> = [T, U];
let pair: Pair<string, number> = ['hello', 10]; // 正确
(7)泛型映射类型
你可以使用泛型来创建映射类型,这些类型将对象中的每个属性从一种类型转换为另一种类型。例如,Partial<T>
和 Readonly<T>
是 TypeScript 标准库中的映射类型。
这只是 TypeScript 泛型的一个简要介绍。泛型为 TypeScript 提供了强大的类型系统和代码重用能力。