TypeScript 的泛型(Generics)是 TypeScript 的一个非常强大的特性,它允许你在编译时定义组件,这些组件可以工作于多种类型的数据上。泛型可以创建可重用的组件,这些组件是独立于任何特定类型的。这意味着你可以编写灵活且可重用的函数、接口和类,这些组件可以接受多种类型的数据作为参数。

泛型函数

泛型函数是在调用时能够接收一个或多个类型参数作为参数的函数。

function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>("myString");  // 类型参数为 string
let output2 = identity(42);  // TypeScript 会自动推断出类型参数为 number

在这个例子中,identity 函数是一个泛型函数,它接受一个类型参数 T 和一个参数 arg,该参数的类型也是 T。函数直接返回它的参数,其返回值的类型也是 T

泛型接口

泛型接口是定义了组件形状的接口,这些组件可以工作于多种类型上。

interface GenericIdentityFn<T> {
    (arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

在这个例子中,GenericIdentityFn 是一个泛型接口,它描述了一个接受单个参数并返回相同类型参数的函数。然后,我们使用这个接口来指定 myIdentity 函数的类型,这个函数能够处理 number 类型的参数。

泛型类

泛型类是在类定义时引入类型参数的一种方式。

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;

    constructor(zeroValue: T, add: (x: T, y: T) => T) {
        this.zeroValue = zeroValue;
        this.add = add;
    }
}

let myGenericNumber = new GenericNumber<number>(0, function(x, y) { return x + y; });

console.log(myGenericNumber.add(1, 2));  // 输出: 3

在这个例子中,GenericNumber 是一个泛型类,它接受一个类型参数 T。这个类有两个属性:zeroValueaddzeroValue 的类型是 T,而 add 是一个函数,它接受两个类型为 T 的参数并返回一个类型为 T 的结果。

泛型约束

有时,你可能想对泛型进行约束,以便它只能被某些类型使用。你可以通过 extends 关键字来约束泛型类型。

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // 现在我们知道 arg 有 length 属性
    return arg;
}

loggingIdentity({length: 10, value: 3});  // 正确
loggingIdentity({value: 3});  // 错误: 没有 length 属性

在这个例子中,我们创建了一个泛型 T,它受到 Lengthwise 接口的约束。这意味着 T 必须有一个 length 属性,并且 loggingIdentity 函数现在可以接受任何具有 length 属性的对象。

泛型是 TypeScript 中的一个非常有用的特性,它允许你编写灵活且可重用的代码,这些代码可以工作于多种类型的数据上。