这也是 TypeScript 中最高频使用的“三剑客”。
它们的本质都是**“基于现有的类型,生成一个新的类型”**。这样你就不用把相似的类型定义写好几遍(DRY 原则)。
为了演示,我们先定义一个基础类型 User(用户):
TypeScript
interface User {
id: number;
name: string;
email: string;
age: number;
isAdmin: boolean;
}
1. Partial<T> (全部变为可选)
作用: 把一个类型的所有属性都变成 可选的 (?)。
场景: 最常见于 “更新数据” 的接口。
比如你只想修改用户的 name,不想传 id 或 email,这时候如果直接用 User 类型就会报错,因为缺属性。
TypeScript
// ❌ 错误做法:直接用 User,必须传所有属性
const updateData: User = { name: "Gemini" }; // 报错:缺少 id, email...
// ✅ 正确做法:使用 Partial
// 等价于:{ id?: number; name?: string; ... }
type UpdateUserDto = Partial<User>;
const updateData: UpdateUserDto = {
name: "Gemini" // 没问题,其他属性不传也可以
};
2. Pick<T, Keys> (只选你要的)
作用: 从一个大类型中,挑选出几个你需要的属性,组成新类型。
场景: “UI 组件传参” 或 “数据预览”。
比如在用户列表页,你只需要展示 name 和 email,不需要把敏感的 isAdmin 或无用的 age 传给组件。
TypeScript
// ✅ 使用 Pick 挑选 name 和 email
// 等价于:{ name: string; email: string; }
type UserPreview = Pick<User, "name" | "email">;
const userCard: UserPreview = {
name: "Gemini",
email: "[email protected]",
// id: 1, // ❌ 报错:UserPreview 里没有 id
// age: 18 // ❌ 报错
};
3. Omit<T, Keys> (排除你不要的)
作用: 从一个大类型中,剔除掉几个你不需要的属性,剩下的组成新类型。它是 Pick 的反义词。
场景: “创建数据”。
比如创建一个新用户时,id 是数据库自动生成的,isAdmin 默认为 false,前端不需要传这两个字段。
TypeScript
// ✅ 使用 Omit 剔除 id 和 isAdmin
// 等价于:{ name: string; email: string; age: number; }
type CreateUserDto = Omit<User, "id" | "isAdmin">;
const newUser: CreateUserDto = {
name: "Gemini",
email: "[email protected]",
age: 20
// id: 1 // ❌ 报错:CreateUserDto 中不包含 id
};
4. 进阶:它们是怎么实现的? (原理篇)
理解原理能让你写出更牛的类型。它们底层主要依赖 映射类型 (Mapped Types) 和 索引查询 (keyof)。
Partial 的源码
原理:遍历 T 的所有 key,加上 ?。
TypeScript
type Partial<T> = {
[P in keyof T]?: T[P];
};
Pick 的源码
原理:遍历你指定的 K (Keys),去 T 里面拿对应的类型。
TypeScript
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
Omit 的源码 (稍微复杂)
原理:先算出 T 的所有 key 中 不包含 K 的部分(用 Exclude),然后再用 Pick 选出来。
TypeScript
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
5. 实战组合拳
在实际开发中,你经常需要组合使用它们。
场景: 更新用户信息时,id 是必须传的(为了知道更新谁),但其他信息是可选的。
TypeScript
// 1. 先用 Pick 选出 id (必填)
type IdPart = Pick<User, "id">;
// 2. 再用 Omit 把 id 排除,剩下的用 Partial 变可选
type RestPart = Partial<Omit<User, "id">>;
// 3. 用 & (交叉类型) 合并
type UpdateUserWithId = IdPart & RestPart;
// 结果:
// {
// id: number; // 必填
// name?: string; // 可选
// email?: string; // 可选
// ...
// }
总结
Partial: 想偷懒,全变可选。
Pick: 做减法,只要这几个。
Omit: 做减法,不要这几个。