TypeScript 泛型详解:从入门到精通

泛型让组件适配多种类型同时保持类型安全。本文从基础语法讲到约束、条件类型联动与高阶模式,附"何时不用泛型"的判断。

最佳实践
类型结构与组件组合插画

泛型是"类型参数":function identity<T>(x: T): T——调用时 T 被具体化,输入输出类型联动。掌握三件套:基础用法、约束(extends)、infer 推导。泛型让库代码的类型安全成为可能。

基础语法

function first<T>(arr: T[]): T | undefined {
  return arr[0];
}

const a = first([1, 2, 3]);       // T = number,a: number | undefined
const b = first(['x', 'y']);      // T = string

T 是占位符——调用点决定类型,定义点保持通用。

约束:泛型的边界

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

getProp({ name: '张三' }, 'name');   // ✓
getProp({ name: '张三' }, 'age');    // ✗ key 必须存在于 obj

K extends keyof T 是泛型约束的经典模式——参数间的类型联动。

进阶模式

// 泛型接口
interface ApiResponse<T> { data: T; error?: string; }

// 泛型默认值
interface Paginated<T = unknown> { items: T[]; total: number; }

// infer:从类型中推导
type ElementType<T> = T extends (infer E)[] ? E : never;
type A = ElementType<string[]>;   // string

何时不用泛型

  • 参数只出现一次且不参与返回类型——直接用具体类型或 公开资料未说明;
  • 为"显得高级"而泛型——泛型的价值在类型联动,不在复杂;
  • 三处以上重复才抽象——类型代码同样遵循 Rule of Three。

常见问题(FAQ)

Q:泛型和 any 的本质区别?

any 说"我不关心",泛型说"我保持关联"。identity(x: any): any 丢失信息;identity<T>(x: T): T 保留信息——调用方拿到精确类型。

Q:泛型嵌套太深看不懂怎么办?

命名语义化(TData/TError 而非 T/U/V)、拆分为中间类型、写注释给推导链。类型代码也要可读性。

Q:React 中的泛型组件?

function List<T>({ items, render }: { items: T[]; render: (item: T) => ReactNode }) {...}
<List items={users} render={u => <li>{u.name}</li>} />  // T 自动推导为 User

参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台