TypeScript泛型介绍 - 泛型函数及类的用法

121 阅读3分钟

引言

TypeScript是一种强类型的JavaScript超集,它引入了泛型(Generics)的概念,以增强代码的重用性和类型安全性。泛型使得我们能够在定义函数、类或接口时不指定具体的类型,而是在使用时再确定类型。本文将深入介绍TypeScript中的泛型,包括泛型函数和泛型类的用法。

泛型函数

泛型函数是一种在函数定义中使用类型参数的方式,使得函数可以适用于多种类型。通过使用泛型,我们可以编写更灵活和通用的函数。

示例:泛型函数

假设我们有一个函数,用于交换两个变量的值:

function swap(a: any, b: any): void {
  const temp = a;
  a = b;
  b = temp;
}

上述函数可以交换任何类型的变量,但是它无法保证类型的安全性。使用泛型可以解决这个问题:

function genericSwap<T>(a: T, b: T): void {
  const temp = a;
  a = b;
  b = temp;
}

在上述代码中,<T>表示类型参数,可以在函数内部使用。调用时,TypeScript会自动根据参数的类型推导出T的具体类型。

泛型约束

有时候,我们需要对泛型进行约束,以确保类型支持某些操作。例如,我们希望对泛型函数进行加法操作:

function add<T>(a: T, b: T): T {
  return a + b; // 报错:操作符“+”不能应用于类型“T”和“T”
}

上述代码会报错,因为T可能是任何类型,而并不是所有类型都支持加法操作。我们可以使用泛型约束来解决这个问题:

interface Addable {
  (a: number, b: number): number;
}

function add<T extends Addable>(a: T, b: T): number {
  return a + b;
}

在上述代码中,我们使用extends关键字来约束泛型类型必须满足Addable接口,即支持加法操作。

泛型类

除了泛型函数,我们还可以创建泛型类,使得类中的属性和方法可以适用于多种类型。

示例:泛型类

假设我们有一个简单的栈(Stack)类:

class Stack {
  private items: any[] = [];

  push(item: any): void {
    this.items.push(item);
  }

  pop(): any {
    return this.items.pop();
  }
}

上述栈类可以存储任何类型的数据,但没有类型安全性。使用泛型类可以解决这个问题:

class GenericStack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T {
    return this.items.pop();
  }
}

在上述代码中,我们使用<T>来表示类型参数,使得栈类可以适用于不同的类型。

泛型约束

和泛型函数一样,我们也可以对泛型类进行约束,以确保类型支持特定操作。例如,我们希望泛型栈类中的元素支持比较操作:

interface Comparable {
  compareTo(other: Comparable): number;
}

class ComparableStack<T extends Comparable> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T {
    return this.items.pop();
  }

  compareItems(a: T, b: T): number {
    return a.compareTo(b);
  }
}

在上述代码中,我们使用extends关键字来约束泛型类型必须满足Comparable接口,即支持比较操作。

结论

泛型是TypeScript中一个强大的特性,使得我们可以编写更通用和类型安全的代码。通过使用泛型函数和泛型类,我们可以在不指定具体类型的情况下,编写适用于多种类型的代码。泛型还可以通过约束来增强类型的支持性。掌握泛型的用法,可以提高代码的可维护性和可复用性。

参考文献