Skip to content

类的泛型支持

类与接口、函数一样,也支持泛型。通过泛型,我们可以创建可重用的组件,使其能够支持多种类型的数据,同时保持严格的类型检查。

基本用法

下面我们实现一个简易的 SimpleSet 类,它可以根据初始化时的数据自动推导存储的元素类型。

typescript
class SimpleSet<T> {
  // 1. 实例属性使用泛型 T
  private elements: Map<T, boolean>;

  constructor(initialElements: T[] = []) {
    this.elements = new Map<T, boolean>();
    initialElements.forEach((element) => this.add(element));
  }

  // 2. 实例方法使用泛型 T,支持链式调用
  add(element: T): this {
    this.elements.set(element, true);
    return this;
  }

  has(element: T): boolean {
    return this.elements.has(element);
  }

  delete(element: T): boolean {
    return this.elements.delete(element);
  }

  values(): T[] {
    return Array.from(this.elements.keys());
  }

  // 3. 静态方法必须声明自己的泛型参数 E
  static of<E>(...elements: E[]): SimpleSet<E> {
    const set = new SimpleSet<E>();
    elements.forEach((element) => set.add(element));
    return set;
  }
}

// 场景 A:显式指定泛型类型
const mySet = new SimpleSet<number>();
mySet.add(1).add(2);

// 场景 B:利用构造函数参数进行自动类型推导
const mySet2 = new SimpleSet(['a', 'b', 'c']); // 推导为 SimpleSet<string>

// 场景 C:调用静态工厂方法
const mySet3 = SimpleSet.of(100, 200, 300); // 推导为 SimpleSet<number>

核心要点

1. 泛型的作用域

类声明上绑定的泛型 T 的作用域涵盖了所有的实例属性实例方法

2. 类型推导

如果在 new 实例化时没有显式指定类型(如 new SimpleSet<number>()),TypeScript 会尝试通过构造函数的参数来推导 T 的具体类型。如果构造函数没有参数且未指定类型,T 默认为 unknown

3. 静态成员的限制

重要限制

类的静态成员不能访问类的泛型参数。

这是因为泛型参数 T 是在实例化时确定的,而静态成员属于类本身,不依赖于实例。因此,如果静态方法需要处理通用类型,必须像上面的 of<E> 方法一样,声明属于自己的泛型参数。

typescript
class Box<T> {
  static value: T; // ❌ 错误:静态成员不能引用类的泛型参数

  static show<U>(item: U) {
    // ✅ 正确:静态方法声明自己的泛型 U
    console.log(item);
  }
}