TypeScript 泛型

TypeScript 泛型(Generics)详解

泛型(Generics) 是 TypeScript 最强大、最核心的特性之一。它允许你创建可重用、类型安全的组件,在不牺牲类型检查的前提下,让函数、类、接口等能够处理多种类型,而不是固定为某种特定类型。

泛型的核心思想:“类型变量” —— 用占位符(如 <T>)表示类型,在使用时再指定具体类型。

1. 泛型函数(Generic Functions)

基础示例:身份函数(Identity Function)
// 普通函数(无泛型)
function identity(arg: number): number {
  return arg;
}

// 使用 any(失去类型安全)
function identityAny(arg: any): any {
  return arg;
}
// let output: string = identityAny(123);  // 不会报错,但不安全

// 泛型版本(推荐)
function identity<T>(arg: T): T {
  return arg;
}

// 使用时指定类型
let numOutput: number = identity<number>(123);
let strOutput: string = identity<string>("hello");

// 或依靠类型推断(最常用)
let boolOutput = identity(true);  // 类型自动推断为 boolean
多个泛型参数
function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

let merged = merge({ name: "Alice" }, { age: 30 });
// merged 类型:{ name: string; } & { age: number; } → { name: string; age: number; }

2. 泛型接口(Generic Interfaces)

interface GenericArray<T> {
  items: T[];
  add(item: T): void;
  get(index: number): T;
}

// 使用
let numberArray: GenericArray<number> = {
  items: [1, 2, 3],
  add(item) { this.items.push(item); },
  get(index) { return this.items[index]; }
};

let stringArray: GenericArray<string> = {
  items: ["a", "b"],
  add(item) { this.items.push(item); },
  get(index) { return this.items[index]; }
};

3. 泛型类(Generic Classes)

class Box<T> {
  private content: T;

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

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

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

// 使用
let numberBox = new Box<number>(100);
numberBox.set(200);
console.log(numberBox.get());  // 200

let stringBox = new Box<string>("hello");
stringBox.set("world");
// stringBox.set(123);  // 错误:类型不匹配

4. 泛型约束(Constraints)—— 限制 T 的范围

默认情况下,T 可以是任何类型,有时需要限制它具有某些属性。

// 约束 T 必须有 length 属性
function printLength<T extends { length: number }>(arg: T): void {
  console.log(arg.length);
}

printLength("hello");     // OK
printLength([1, 2, 3]);   // OK
printLength({ length: 10, value: 5 });  // OK
// printLength(123);      // 错误:number 没有 length
使用 keyof 约束键
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

let person = { name: "Alice", age: 30 };
let name = getProperty(person, "name");  // 类型:string
let age = getProperty(person, "age");    // 类型:number
// getProperty(person, "email");         // 错误:email 不存在

5. 默认泛型参数(Default Type Parameters,TS 2.3+)

interface ApiResponse<T = any> {
  data: T;
  status: number;
}

// 使用时可省略
let response: ApiResponse = { data: "ok", status: 200 };

// 或指定
let jsonResponse: ApiResponse<string[]> = {
  data: ["a", "b"],
  status: 200
};

6. 常见泛型应用场景

场景示例
数组工具函数function first<T>(arr: T[]): T
PromisePromise<T>(TS 内置)
React 组件function List<T>(props: { items: T[] })
类型安全的工厂函数function create<T>(c: new () => T): T
映射类型type Partial<T> = { [K in keyof T]?: T[K] }

7. 内置泛型工具类型(Utility Types)

TypeScript 自带大量基于泛型的工具类型:

类型作用示例
Partial<T>所有属性可选Partial<User>
Required<T>所有属性必选
Readonly<T>所有属性只读
Pick<T, K>挑选属性Pick<User, "name" | "age">
Omit<T, K>排除属性Omit<User, "password">
Record<K, T>创建键值对象类型Record<string, number>
ReturnType<T>获取函数返回值类型ReturnType<typeof fetch>
Parameters<T>获取函数参数元组

8. 最佳实践建议

建议说明
优先让 TS 自动推断泛型identity("hi") 而非 identity<string>("hi")
使用约束避免过度宽松T extends { id: number }
泛型函数名后写 <T>保持一致性
避免泛型嵌套过深可读性优先
结合接口/类使用泛型构建可复用组件
多用内置工具类型减少手动编写复杂类型

小结:泛型速查表

写法含义
function fn<T>(arg: T): T基本泛型函数
T extends U约束 T 必须继承 U
K extends keyof T键约束
class Box<T>泛型类
interface List<T>泛型接口
Promise<T>内置泛型示例
Partial<T>工具类型示例

泛型是 TypeScript 从“类型安全脚本语言”提升为“工业级类型系统”的关键。掌握泛型后,你可以编写高度可复用、类型严谨的库和应用(如 React、NestJS、RxJS 等都大量使用泛型)。

如果您想看更多实战示例(如泛型组件在 React 中的使用高级条件泛型泛型递归类型),或者需要一个完整的泛型工具库示例,请告诉我!

文章已创建 3383

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部