一文掌握 TypeScript 工具类型:Record、Partial、Omit、Pick 等实战用法

564 阅读3分钟

一文搞懂 TypeScript 常用泛型工具类型(Record、Partial、Omit、Pick 等)

TypeScript 内置了一批 泛型工具类型,比如 RecordPartialOmitPick 等,它们能基于已有类型快速生成新类型,避免重复定义,让类型既安全又灵活。
如果你停留在只会“用”,却不太理解 为什么会出现原理是什么最佳实践如何选型。本文就带你从 痛点 → 工具类型 → 实战 → 原理,一次性搞透。

1. 为什么会出现?

早期 TypeScript 开发的痛点:

  • 相似的类型要重复写多份
  • 为了适配不同场景,需要频繁复制粘贴类型定义
  • 一旦源类型变动,所有相关类型都要手动更新

泛型工具类型就是为了解决这些问题:

  • 减少重复:用组合和派生代替重复声明
  • 提升安全:编译器帮你检查类型错误
  • 更灵活:业务变动时派生类型自动适配

2. 常用工具类型列表

工具类型作用简述原理
Record<K, T>将键集合 K 映射到类型 T映射类型批量生成属性
Partial<T>将所有属性设为可选? 修饰符映射
Omit<T, K>T 排除 K 属性Pick + Exclude
Pick<T, K>只保留 K 指定属性映射类型选择
Required<T>将所有属性设为必填去掉 ? 修饰符
Readonly<T>将所有属性设为只读readonly 修饰符映射
Exclude<T, U>从联合类型 T 排除类型 U条件类型
Extract<T, U>从联合类型 T 提取 U 类型条件类型
NonNullable<T>排除 nullundefined条件类型
ReturnType<F>获取函数返回值类型infer 推导
InstanceType<C>获取构造函数实例类型infer 推导

3. 使用场景与原理

3.1 Record:权限表

type Role = 'admin' | 'editor' | 'viewer';
type Permission = 'read' | 'write' | 'delete';

const rolePermissions: Record<Role, Permission[]> = {
  admin: ['read', 'write', 'delete'],
  editor: ['read', 'write'],
  viewer: ['read']
};

原理Record<K, T> 本质就是“用 K 的所有键生成一组属性”:

type Record<K extends keyof any, T> = {
  [P in K]: T;
}

3.2 Partial:更新用户信息

interface UserProfile {
  id: number;
  name: string;
  email: string;
}
function updateUser(id: number, updates: Partial<UserProfile>) {
  // ...
}

updateUser(1, { email: 'new@example.com' });

原理:通过映射类型给所有属性加上 ?

type Partial<T> = {
  [P in keyof T]?: T[P];
}

3.3 Omit:去除敏感字段

interface User {
  id: number;
  name: string;
  password: string
}
type SafeUser = Omit<User, 'password'>;

原理:其实就是 Pick + Exclude 的组合:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>

3.4 Pick:只要部分字段

type UserNameEmail = Pick<UserProfile, 'name' | 'email'>;

原理:只保留 K 中的键:

type Pick<T, K extends keyof any> = {
  [P in K]: T[P]
}

3.5 Required:接口必填化

type StrictUser = Required<Partial<UserProfile>>;

3.6 Readonly:让属性只读

const config: Readonly<{ apiUrl: string }> = {
  apiUrl: 'https://api.example.com'
};
config.apiUrl = '' // 报错

3.7 Exclude & Extract:联合类型过滤

type T = 'a' | 'b' | 'c';

type WithoutB = Exclude<T, 'b'>; // 'a' | 'c'
type OnlyB = Extract<T, 'b'>; // 'b'

对比:

  • Pick/Omit 好比一个 对象裁剪器:我有一张“用户表单”,我要么只留下 name/email(Pick),要么去掉 password(Omit)。
  • Exclude/Extract 好比一个 集合过滤器:我有一个集合 {'a','b','c'},我去掉 b(Exclude)或只要 b(Extract)。

3.8 NonNullable:去掉 null/undefined

type Value = string | null | undefined;
type SafeValue = NonNullable<Value>; // string

3.9 ReturnType & InstanceType:类型推导

function getUser() {
  return { id: 1, name: 'Alice' };
}
type UserReturn = ReturnType<typeof getUser>; 
// { id: number; name: string; }

class Person { name = 'Bob'; }
type PersonInstance = InstanceType<typeof Person>; 
// Person

4. 工具类型的实现思路

常见实现方式有三类:

  1. 映射类型Record / Partial / Pick / Omit / Readonly / Required

  2. 条件类型Exclude / Extract / NonNullable

  3. infer 推导ReturnType / InstanceType

5. 最佳实践与注意事项

  • 避免过度嵌套Partial<Required<Pick<...>>> 会让类型难以阅读,尽量保持扁平。
  • 业务分层使用:比如 DTO 层用 Omit 去掉数据库 ID,前端表单用 Partial 允许字段可选。
  • 结合自定义类型:内置工具类型不够时,可以通过条件类型 + 映射类型组合,写出自己的工具类型。

参考更多资料: