TypeScript 泛型的使用

理解 TypeScript 泛型的概念、使用方式和应用场景

问题

TypeScript 中泛型是什么?如何使用?

解答

什么是泛型

泛型允许我们在定义函数、接口或类时不预先指定具体类型,而是在使用时再指定类型。这样可以创建灵活、可重用的代码。

例如,如果要实现一个函数接收并返回相同类型的参数,不使用泛型会导致代码重复:

function returnItem(para: number): number {
    return para
}

function returnItem(para: string): string {
    return para
}

使用泛型可以简化为:

function returnItem<T>(para: T): T {
    return para
}

函数中使用泛型

定义单个类型参数:

function returnItem<T>(para: T): T {
    return para
}

定义多个类型参数:

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]]
}

swap([7, 'seven']) // ['seven', 7]

接口中使用泛型

interface ReturnItemFn<T> {
    (para: T): T
}

const returnItem: ReturnItemFn<number> = para => para

类中使用泛型

class Stack<T> {
    private arr: T[] = []

    public push(item: T) {
        this.arr.push(item)
    }

    public pop(): T | undefined {
        return this.arr.pop()
    }
}

const stack = new Stack<number>()

泛型约束

使用 extends 约束泛型类型:

function getValue<T extends object, U extends keyof T>(obj: T, key: U) {
    return obj[key]
}

const obj = { a: 1, b: 2 }
getValue(obj, 'a') // 正确
getValue(obj, 'c') // 错误:'c' 不是 obj 的属性

多类型约束

通过接口继承实现多类型约束:

interface FirstInterface {
    doSomething(): number
}

interface SecondInterface {
    doSomethingElse(): string
}

interface ChildInterface extends FirstInterface, SecondInterface {}

class Demo<T extends ChildInterface> {
    private genericProperty: T

    constructor(genericProperty: T) {
        this.genericProperty = genericProperty
    }
}

关键点

  • 泛型通过 <T> 形式表示,在使用时才指定具体类型
  • 可以在函数、接口、类中使用泛型
  • 使用 extends 关键字约束泛型类型范围
  • keyof 可以获取对象属性的联合类型,常用于索引类型约束
  • 通过接口继承可以实现多类型约束