CodeL
以前端为翼,以 AI 为脑,向全栈而行
2026-03-31

TypeScript 泛型完整教程

TypeScript 泛型完整教程 从零到精通,覆盖泛型函数、泛型接口、泛型类、泛型约束、实战应用等核心场景。 目录 一、核心概念 二、基础使用 三、进阶用法 四、实战场景 五、常见问题 六、总结速记 一、核心概念 1....

TypeScript 泛型完整教程 #

从零到精通,覆盖泛型函数、泛型接口、泛型类、泛型约束、实战应用等核心场景。


目录 #


一、核心概念 #

1.1 什么是泛型? #

大白话解释

泛型就是"类型的模板"——让你写一个函数/类/接口,能适配多种类型,而不是只固定一种类型。

类比理解

想象你去餐厅点餐:

  • 固定类型:菜单只有"红烧肉",想吃别的?没有。
  • 泛型:菜单写着"炒菜(可自选食材)",你想吃炒牛肉就选牛肉,想吃炒青菜就选青菜。

在 TypeScript 中:

  • 固定类型function add(a: number, b: number) → 只能加数字
  • 泛型function add<T>(a: T, b: T) → T 可以是 number、string、任何类型

1.2 为什么需要泛型? #

问题场景:写一个"返回输入值"的函数。

// 方案一:固定类型(只能用 number)
function identity(arg: number): number {
  return arg;
}
identity(100);      // ✅ OK
identity("hello");  // ❌ 报错:不能传字符串
 
// 方案二:用 any(丢失类型信息)
function identity(arg: any): any {
  return arg;
}
identity(100);      // 返回值类型是 any,不是 number
identity("hello");  // 返回值类型是 any,不是 string
// 问题:传入 number,返回值应该是 number,但 TS 不知道

泛型解决方案

function identity<T>(arg: T): T {
  return arg;
}
 
identity<number>(100);     // 返回值类型是 number ✅
identity<string>("hello"); // 返回值类型是 string ✅
 
// 更方便:自动推断类型
identity(100);     // TS 自动推断 T = number
identity("hello"); // TS 自动推断 T = string

1.3 泛型的核心名词 #

名词 解释 示例
泛型参数 <T> 定义的类型占位符 <T><K, V>
类型变量 泛型参数的具体名称 T(常用)、K(键)、V(值)
泛型函数 带泛型参数的函数 function fn<T>(arg: T): T
泛型接口 带泛型参数的接口 interface Container<T> { value: T }
泛型类 哈泛型参数的类 class Box<T> { content: T }
泛型约束 限制泛型的范围 <T extends string>
类型推断 TS 自动推断泛型类型 identity(100) → 自动推断 T = number

二、基础使用 #

2.1 泛型函数 #

最简单的泛型函数

// 定义泛型函数
function identity<T>(arg: T): T {
  return arg;
}
 
// 使用方式一:显式指定类型
const num = identity<number>(100);      // num 类型是 number
const str = identity<string>("hello");  // str 类型是 string
 
// 使用方式二:自动推断类型(推荐)
const num2 = identity(100);      // TS 自动推断 T = number
const str2 = identity("hello");  // TS 自动推断 T = string

多泛型参数

// 两个泛型参数
function swap<K, V>(key: K, value: V): [K, V] {
  return [key, value];
}
 
const result = swap("name", "张三");  // result 类型是 [string, string]
const result2 = swap(1, 100);        // result2 类型是 [number, number]

箭头函数泛型

// 箭头函数写法
const identity = <T>(arg: T): T => arg;
 
// 多参数箭头函数
const createPair = <K, V>(key: K, value: V): [K, V] => [key, value];

2.2 泛型接口 #

定义泛型接口

// 泛型接口:容器
interface Container<T> {
  value: T;
  getValue(): T;
}
 
// 使用
const numberContainer: Container<number> = {
  value: 100,
  getValue() { return this.value; }
};
 
const stringContainer: Container<string> = {
  value: "hello",
  getValue() { return this.value; }
};

泛型函数类型接口

// 定义泛型函数类型
interface GenericFunction<T> {
  (arg: T): T;
}
 
// 实现
const identity: GenericFunction<number> = (arg) => arg;
identity(100);  // ✅ OK
identity("hello");  // ❌ 报错:类型不匹配

2.3 泛型类 #

定义泛型类

// 泛型类:盒子
class Box<T> {
  private content: T;
  
  constructor(content: T) {
    this.content = content;
  }
  
  getContent(): T {
    return this.content;
  }
  
  setContent(content: T): void {
    this.content = content;
  }
}
 
// 使用
const numberBox = new Box<number>(100);
numberBox.getContent();       // 返回 number
numberBox.setContent(200);    // ✅ OK
numberBox.setContent("hi");   // ❌ 报错:类型不匹配
 
const stringBox = new Box<string>("hello");
stringBox.getContent();       // 返回 string

泛型类的实际应用

// 泛型类:存储器
class Storage<T> {
  private items: T[] = [];
  
  add(item: T): void {
    this.items.push(item);
  }
  
  getAll(): T[] {
    return this.items;
  }
  
  find(predicate: (item: T) => boolean): T | undefined {
    return this.items.find(predicate);
  }
}
 
// 使用:存用户
interface User {
  id: number;
  name: string;
}
 
const userStorage = new Storage<User>();
userStorage.add({ id: 1, name: "张三" });
userStorage.add({ id: 2, name: "李四" });
userStorage.find(u => u.id === 1);  // 返回 User | undefined

2.4 泛型数组 #

// 泛型数组函数
function getFirst<T>(arr: T[]): T | undefined {
  return arr[0];
}
 
getFirst([1, 2, 3]);        // 返回 number | undefined
getFirst(["a", "b", "c"]);  // 返回 string | undefined
getFirst([]);               // 返回 undefined
 
// 泛型数组方法
function mapArray<T, U>(arr: T[], fn: (item: T) => U): U[] {
  return arr.map(fn);
}
 
const numbers = [1, 2, 3];
const doubled = mapArray(numbers, n => n * 2);  // doubled 类型是 number[]
const strings = mapArray(numbers, n => n.toString());  // strings 类型是 string[]

三、进阶用法 #

3.1 泛型约束 #

问题:泛型太自由,访问不存在属性会报错。

function getLength<T>(arg: T): number {
  return arg.length;  // ❌ 报错:T 可能没有 length 属性
}

解决:用 extends 约束泛型必须有某些属性。

// 定义约束接口
interface HasLength {
  length: number;
}
 
// 泛型约束:T 必须有 length 属性
function getLength<T extends HasLength>(arg: T): number {
  return arg.length;  // ✅ OK
}
 
// 使用
getLength("hello");     // ✅ string 有 length
getLength([1, 2, 3]);   // ✅ array 有 length
getLength({ length: 10 });  // ✅ 对象有 length 属性
getLength(100);         // ❌ 报错:number 没有 length

常用约束类型

约束 说明 示例
T extends string T 必须是 string 或其子类型 function fn<T extends string>(arg: T)
T extends number T 必须是 number 或其子类型 function fn<T extends number>(arg: T)
T extends object T 必须是对象类型 function fn<T extends object>(arg: T)
T extends { prop: Type } T 必须有指定属性 function fn<T extends { id: number }>(arg: T)

3.2 keyof 约束(获取对象的属性) #

问题:写一个函数获取对象的某个属性值,但要确保属性名存在。

function getProperty(obj: any, key: string): any {
  return obj[key];  // ❌ 不安全,key 可能不存在
}

解决:用 keyof 约束 key 必须是对象的属性名。

// keyof 约束:K 必须是 T 的属性名之一
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
 
// 使用
interface User {
  id: number;
  name: string;
  age: number;
}
 
const user: User = { id: 1, name: "张三", age: 25 };
 
getProperty(user, "id");    // 返回 number ✅
getProperty(user, "name");  // 返回 string ✅
getProperty(user, "email"); // ❌ 报错:User 没有 email 属性

3.3 泛型默认类型 #

// 泛型默认类型:如果不指定,就用默认类型
interface Container<T = string> {
  value: T;
}
 
// 不指定类型,默认是 string
const strContainer: Container = { value: "hello" };
 
// 指定类型
const numContainer: Container<number> = { value: 100 };

实际应用:API 响应类型。

// API 响应泛型,默认 data 是 unknown
interface ApiResponse<T = unknown> {
  code: number;
  message: string;
  data: T;
}
 
// 不知道 data 类型时
const response: ApiResponse = {
  code: 200,
  message: "success",
  data: null  // data 类型是 unknown
};
 
// 知道 data 类型时
interface User {
  id: number;
  name: string;
}
 
const userResponse: ApiResponse<User> = {
  code: 200,
  message: "success",
  data: { id: 1, name: "张三" }  // data 类型是 User
};

3.4 泛型与条件类型 #

// 条件类型:根据泛型类型返回不同结果
type IsString<T> = T extends string ? "yes" : "no";
 
type A = IsString<string>;  // "yes"
type B = IsString<number>;  // "no"
type C = IsString<"hello">; // "yes"(字符串字面量也是 string 子类型)

实际应用:提取函数返回类型

// 提取函数的返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
 
function getUser(): { id: number; name: string } {
  return { id: 1, name: "张三" };
}
 
type UserReturn = ReturnType<typeof getUser>;  // { id: number; name: string }

3.5 泛型工具类型(TypeScript 内置) #

TypeScript 提供了多个泛型工具类型:

工具类型 说明 示例
Partial<T> 所有属性变可选 Partial<User>
Required<T> 所有属性变必选 Required<User>
Readonly<T> 所有属性变只读 Readonly<User>
Pick<T, K> 选取部分属性 `Pick<User, 'id'
Omit<T, K> 排除部分属性 Omit<User, 'age'>
Record<K, V> 创建对象类型 Record<string, number>
ReturnType<T> 获取函数返回类型 ReturnType<typeof fn>

使用示例

interface User {
  id: number;
  name: string;
  age: number;
  email: string;
}
 
// Partial:所有属性可选
type PartialUser = Partial<User>;
// { id?: number; name?: string; age?: number; email?: string; }
 
// Pick:选取部分属性
type UserNameAndId = Pick<User, 'id' | 'name'>;
// { id: number; name: string; }
 
// Omit:排除部分属性
type UserWithoutEmail = Omit<User, 'email'>;
// { id: number; name: string; age: number; }
 
// Record:创建键值对类型
type UserMap = Record<number, User>;
// { [key: number]: User }

四、实战场景 #

场景 1:API 请求封装 #

需求:封装一个通用的 fetch 函数,返回类型自动推断。

// 泛型 API 请求函数
async function fetchApi<T>(url: string): Promise<T> {
  const response = await fetch(url);
  const data = await response.json();
  return data as T;
}
 
// 定义响应类型
interface UserResponse {
  id: number;
  name: string;
  email: string;
}
 
interface ProductResponse {
  id: number;
  title: string;
  price: number;
}
 
// 使用:自动推断返回类型
const user = await fetchApi<UserResponse>('/api/user/1');
console.log(user.name);  // ✅ TS 知道 name 是 string
 
const products = await fetchApi<ProductResponse[]>('/api/products');
products.forEach(p => console.log(p.title));  // ✅ TS 知道 title 是 string

场景 2:表单验证 #

需求:通用表单验证器,支持不同表单字段类型。

// 定义验证规则类型
interface ValidationRule<T> {
  required?: boolean;
  minLength?: number;  // 仅用于 string
  min?: number;        // 仅用于 number
  max?: number;        // 仅用于 number
  pattern?: RegExp;    // 仅用于 string
  validator?: (value: T) => boolean;
}
 
// 泛型表单字段
interface FormField<T> {
  value: T;
  rules: ValidationRule<T>[];
  error?: string;
}
 
// 验证函数
function validateField<T>(field: FormField<T>): boolean {
  for (const rule of field.rules) {
    if (rule.required && !field.value) {
      field.error = "此字段必填";
      return false;
    }
    // 其他验证规则...
  }
  return true;
}
 
// 使用:登录表单
interface LoginForm {
  username: FormField<string>;
  password: FormField<string>;
}
 
const loginForm: LoginForm = {
  username: {
    value: "",
    rules: [
      { required: true },
      { minLength: 3, validator: v => v.length >= 3 }
    ]
  },
  password: {
    value: "",
    rules: [
      { required: true },
      { minLength: 6 }
    ]
  }
};
 
validateField(loginForm.username);  // ✅ 泛型验证

场景 3:状态管理(简化版 Redux) #

需求:通用状态管理器,支持不同状态类型。

// 泛型状态管理器
class StateManager<T> {
  private state: T;
  private listeners: ((state: T) => void)[] = [];
  
  constructor(initialState: T) {
    this.state = initialState;
  }
  
  getState(): T {
    return this.state;
  }
  
  setState(newState: T | ((prev: T) => T)): void {
    if (typeof newState === 'function') {
      this.state = (newState as Function)(this.state);
    } else {
      this.state = newState;
    }
    this.listeners.forEach(listener => listener(this.state));
  }
  
  subscribe(listener: (state: T) => void): () => void {
    this.listeners.push(listener);
    return () => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }
}
 
// 使用:用户状态
interface UserState {
  user: { id: number; name: string } | null;
  loading: boolean;
  error: string | null;
}
 
const userStore = new StateManager<UserState>({
  user: null,
  loading: false,
  error: null
});
 
// 订阅状态变化
userStore.subscribe(state => {
  console.log('用户状态更新:', state);
});
 
// 更新状态
userStore.setState({ user: { id: 1, name: "张三" }, loading: false, error: null });
 
// 函数式更新
userStore.setState(prev => ({
  ...prev,
  loading: true
}));

场景 4:事件发射器 #

需求:通用事件系统,支持不同事件类型和数据。

// 泛型事件类型
type EventHandler<T> = (data: T) => void;
 
// 泛型事件发射器
class EventEmitter<EventMap extends Record<string, any>> {
  private handlers: Map<keyof EventMap, EventHandler<any>[]> = new Map();
  
  on<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): void {
    const existing = this.handlers.get(event) || [];
    this.handlers.set(event, [...existing, handler]);
  }
  
  emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void {
    const handlers = this.handlers.get(event) || [];
    handlers.forEach(handler => handler(data));
  }
  
  off<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): void {
    const handlers = this.handlers.get(event) || [];
    this.handlers.set(event, handlers.filter(h => h !== handler));
  }
}
 
// 使用:定义事件类型
interface AppEvents {
  'user:login': { userId: number; name: string };
  'user:logout': { userId: number };
  'message:send': { to: number; content: string };
  'notification': { type: 'success' | 'error'; message: string };
}
 
const emitter = new EventEmitter<AppEvents>();
 
// 监听事件(类型安全)
emitter.on('user:login', data => {
  console.log(`用户登录: ${data.name}`);  // data 类型自动推断
});
 
emitter.on('notification', data => {
  if (data.type === 'success') {
    console.log(`成功: ${data.message}`);
  }
});
 
// 发射事件
emitter.emit('user:login', { userId: 1, name: "张三" });
emitter.emit('notification', { type: 'success', message: "操作成功" });
 
// 错误示例:类型不匹配会报错
emitter.emit('user:login', { name: "张三" });  // ❌ 缺少 userId
emitter.emit('notification', { type: 'info', message: "..." });  // ❌ type 不是 'success' | 'error'

场景 5:组件 Props 类型(React) #

需求:React 组件 Props 类型复用。

// 基础 Props
interface BaseProps {
  className?: string;
  style?: React.CSSProperties;
  children?: React.ReactNode;
}
 
// 泛型组件 Props
interface ListProps<T> extends BaseProps {
  items: T[];
  renderItem: (item: T, index: number) => React.ReactNode;
  onItemClick?: (item: T) => void;
}
 
// 泛型组件
function List<T>({ items, renderItem, onItemClick, className }: ListProps<T>) {
  return (
    <ul className={className}>
      {items.map((item, index) => (
        <li 
          key={index} 
          onClick={() => onItemClick?.(item)}
        >
          {renderItem(item, index)}
        </li>
      ))}
    </ul>
  );
}
 
// 使用:用户列表
interface User {
  id: number;
  name: string;
  avatar: string;
}
 
<List<User>
  items={[
    { id: 1, name: "张三", avatar: "/avatar1.jpg" },
    { id: 2, name: "李四", avatar: "/avatar2.jpg" }
  ]}
  renderItem={(user) => (
    <div>
      <img src={user.avatar} alt={user.name} />
      <span>{user.name}</span>
    </div>
  )}
  onItemClick={(user) => console.log('点击:', user.id)}
/>
 
// 使用:商品列表
interface Product {
  id: number;
  title: string;
  price: number;
}
 
<List<Product>
  items={[{ id: 1, title: "商品A", price: 100 }]}
  renderItem={(product) => (
    <div>
      <h3>{product.title}</h3>
      <p>¥{product.price}</p>
    </div>
  )}
/>

五、常见问题 #

Q1:什么时候用泛型,什么时候用 any? #

情况 选择 原因
需要保留类型信息 泛型 identity<T> 返回值类型与参数一致
真的不关心类型 any JSON.parse 返回值真的不确定
可以是多种类型 泛型 + 约束 `<T extends string
// 泛型:保留类型信息
function identity<T>(arg: T): T {
  return arg;
}
const num = identity(100);  // num 是 number
 
// any:丢失类型信息
function identityAny(arg: any): any {
  return arg;
}
const numAny = identityAny(100);  // numAny 是 any,不是 number

Q2:泛型参数命名规范? #

常用名称 说明 使用场景
T Type(类型) 单泛型参数
K Key(键) 对象键
V Value(值) 对象值、Map
E Element(元素) 数组元素
R Return(返回) 函数返回值
U 第二个类型 多泛型参数
// 单泛型
function identity<T>(arg: T): T {}
 
// 对象键值
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {}
 
// Map 类型
interface Map<K, V> {
  get(key: K): V;
  set(key: K, value: V): void;
}
 
// 函数返回值
type ReturnType<T extends (...args: any[]) => any> = 
  T extends (...args: any[]) => infer R ? R : never;

Q3:泛型可以嵌套吗? #

可以,但要注意类型复杂度。

// 泛型嵌套
interface Container<T> {
  value: T;
}
 
interface NestedContainer<T> {
  outer: Container<T>;
  inner: Container<Container<T>>;
}
 
const nested: NestedContainer<string> = {
  outer: { value: "outer" },
  inner: { value: { value: "inner" } }
};
 
// 复杂嵌套(避免过度使用)
type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};

Q4:如何在箭头函数中使用泛型? #

注意 .tsx 文件中 <T> 可能被误认为是 JSX 标签。

// .ts 文件:正常写
const identity = <T>(arg: T): T => arg;
 
// .tsx 文件:加 extends 避免歧义
const identity = <T extends unknown>(arg: T): T => arg;
// 或
const identity = <T,>(arg: T): T => arg;  // 加逗号区分

Q5:泛型约束和继承的区别? #

概念 说明 示例
泛型约束 限制泛型类型范围 <T extends string>
接口继承 扩展接口定义 interface A extends B
// 泛型约束:限制 T 必须是 string 或其子类型
function fn<T extends string>(arg: T): T {
  return arg;
}
fn("hello");      // ✅ OK
fn(100);          // ❌ 报错:number 不满足约束
 
// 接口继承:扩展接口
interface Base { id: number; }
interface User extends Base { name: string; }
// User = { id: number; name: string; }

六、总结速记 #

类型 核心要点
概念 泛型 = 类型模板,适配多种类型
语法 <T> 定义泛型参数
函数 function fn<T>(arg: T): T
接口 interface Container<T> { value: T }
class Box<T> { content: T }
约束 <T extends HasLength> 限制泛型范围
keyof <K extends keyof T> 确保 key 存在
工具类型 Partial<T>Pick<T, K>Omit<T, K>Record<K, V>

附录 #

A. 泛型语法速查 #

// 泛型函数
function fn<T>(arg: T): T {}
const fn = <T>(arg: T): T => arg;
 
// 泛型接口
interface Container<T> { value: T; }
 
// 泛型类
class Box<T> { content: T; }
 
// 泛型约束
function fn<T extends { length: number }>(arg: T): number {
  return arg.length;
}
 
// keyof 约束
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {}
 
// 默认类型
interface ApiResponse<T = unknown> { data: T; }
 
// 多泛型
function map<T, U>(arr: T[], fn: (item: T) => U): U[] {}

B. 泛型工具类型速查 #

工具类型 说明 示例
Partial<T> 所有属性可选 Partial<User>
Required<T> 所有属性必选 Required<User>
Readonly<T> 所有属性只读 Readonly<User>
Pick<T, K> 选取属性 Pick<User, 'id' | 'name'>
Omit<T, K> 排除属性 Omit<User, 'email'>
Record<K, V> 键值对类型 Record<string, number>
ReturnType<T> 函数返回类型 ReturnType<typeof fn>
Parameters<T> 函数参数类型 Parameters<typeof fn>
NonNullable<T> 排除 null/undefined NonNullable<string | null>

C. 推荐资源 #

名称 链接 说明
TypeScript 官方文档 https://www.typescriptlang.org/docs/handbook/2/generics.html ✅ 官方泛型教程
TypeScript Handbook https://www.typescriptlang.org/docs/handbook/ ✅ 完整手册
TypeScript Playground https://www.typescriptlang.org/play ✅ 在线练习
TypeScript Deep Dive https://basarat.gitbook.io/typescript/ ✅ 深入教程

最后更新:2026-03-28