阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 泛型类

泛型类

作者:陈川 阅读数:17020人阅读 分类: TypeScript

TypeScript 的泛型类允许开发者创建可复用的组件,这些组件能够处理多种数据类型而不牺牲类型安全。泛型类通过类型参数在类定义时引入灵活性,使得同一个类可以适应不同的类型需求。

泛型类的基本语法

泛型类在类名后使用尖括号 <T> 声明类型参数,T 是类型变量的占位符,实际使用时会被具体类型替换。例如:

class Box<T> {
  private content: T;

  constructor(value: T) {
    this.content = value;
  }

  getValue(): T {
    return this.content;
  }
}

const numberBox = new Box<number>(42);
const stringBox = new Box<string>("Hello");

这里 Box 类通过 <T> 声明泛型参数,content 属性和 getValue 方法的类型都依赖于 T。实例化时分别指定 numberstring 类型,使得类型检查能够针对不同场景生效。

泛型约束与默认类型

泛型类可以通过 extends 添加约束,限制类型参数的范围。同时支持为泛型参数提供默认类型:

interface HasLength {
  length: number;
}

class Container<T extends HasLength = string> {
  constructor(private data: T) {}

  logLength(): void {
    console.log(this.data.length);
  }
}

const strContainer = new Container("abc"); // 使用默认类型 string
const arrContainer = new Container<number[]>([1, 2, 3]); // 显式指定类型

此例中 T 必须满足 HasLength 接口,且默认类型为 string。尝试使用不包含 length 属性的类型会导致编译错误。

多类型参数应用

泛型类支持多个类型参数,适用于需要处理多种关联类型的场景:

class Pair<K, V> {
  constructor(
    public key: K,
    public value: V
  ) {}

  swap(): Pair<V, K> {
    return new Pair(this.value, this.key);
  }
}

const nameAge = new Pair<string, number>("Alice", 30);
const swapped = nameAge.swap(); // 类型变为 Pair<number, string>

Pair 类通过 <K, V> 定义两个泛型参数,在 swap 方法中实现类型位置的互换,保持类型系统的完整性。

静态成员的限制

需注意泛型类的静态成员不能引用类的类型参数:

class GenericStatic<T> {
  static defaultValue: T; // 错误:静态成员不能引用类型参数
  instanceValue: T; // 正确
}

这是因为静态成员属于类本身而非实例,而泛型参数在实例化时才会确定具体类型。

与泛型接口结合使用

泛型类可以实现泛型接口,形成更灵活的类型体系:

interface IRepository<T> {
  getById(id: string): T;
  save(entity: T): void;
}

class UserRepository implements IRepository<User> {
  getById(id: string): User {
    // 实现逻辑
  }
  save(user: User): void {
    // 实现逻辑
  }
}

复杂类型推断示例

泛型类在复杂类型场景中能自动推断类型关系:

class TreeNode<T> {
  constructor(
    public value: T,
    public left: TreeNode<T> | null = null,
    public right: TreeNode<T> | null = null
  ) {}
}

const tree = new TreeNode(1, new TreeNode(2), new TreeNode(3));
// 自动推断为 TreeNode<number>

类型擦除的运行时行为

虽然 TypeScript 在编译时会进行类型检查,但运行时泛型类型信息会被擦除:

class Erasure<T> {
  constructor(private data: T) {}
}

const instance1 = new Erasure<string>("test");
const instance2 = new Erasure<number>(123);

console.log(instance1 instanceof Erasure); // true
console.log(instance2 instanceof Erasure); // true
// 运行时无法区分 Erasure<string> 和 Erasure<number>

高级模式:递归泛型

泛型类可以定义递归类型结构,适用于自引用数据模型:

class NestedArray<T> {
  constructor(public items: Array<T | NestedArray<T>>) {}

  flatten(): T[] {
    return this.items.reduce((acc: T[], item) => {
      return acc.concat(item instanceof NestedArray ? item.flatten() : item);
    }, []);
  }
}

const nested = new NestedArray([1, [new NestedArray([2, 3]), 4]);
console.log(nested.flatten()); // [1, 2, 3, 4]

工厂函数与泛型类结合

通过工厂函数创建泛型类实例时,可以保留完整的类型信息:

function createComponent<T>(ctor: new () => T): T {
  return new ctor();
}

class Button {
  click() {
    console.log("Clicked!");
  }
}

const button = createComponent(Button); // 类型推断为 Button
button.click();

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:泛型接口

下一篇:泛型约束

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌