Logo
Section 1 / 8

实用类型:Pick、Omit、Partial 和 Required

掌握最有用的内置工具类型,编写更简洁、更安全且更易维护的 TypeScript 代码。

导入

实用类型:Pick、Omit、Partial 和 Required

掌握最有用的内置工具类型,编写更简洁、更安全且更易维护的 TypeScript 代码。

1type FullUser = { 2 id: string; 3 name: string; 4 email: string; 5 passwordHash: string; 6}; 7 8type PublicUser = Pick<FullUser, "id" | "name">; 9 10const view: PublicUser = { 11 id: "u123", 12 name: "Zara", 13}; 14 15console.log(view);
1type Config = { 2 apiKey: string; 3 endpoint: string; 4 retries: number; 5}; 6 7type ClientConfig = Omit<Config, "apiKey">; 8 9const safe: ClientConfig = { 10 endpoint: "/api", 11 retries: 2, 12}; 13 14console.log(safe);
1type User = { 2 id: string; 3 name: string; 4 email: string; 5}; 6 7type UpdatePayload = Partial<Omit<User, "id">>; 8 9const update: UpdatePayload = { 10 name: "Tasha", 11}; 12 13console.log(update);
1type FormDraft = { 2 name?: string; 3 email?: string; 4}; 5 6type FinalForm = Required<FormDraft>; 7 8const form: FinalForm = { 9 name: "Alok", 10 email: "a@example.com", 11}; 12 13console.log(form);
1type Product = { 2 sku: string; 3 name: string; 4 price: number; 5 tags?: string[]; 6}; 7 8type ProductDraftMap = Record<string, Partial<Omit<Product, "sku">>>; 9 10const drafts: ProductDraftMap = { 11 p1: { name: "Shirt" }, 12 p2: { price: 19.99, tags: ["sale"] }, 13}; 14 15console.log(drafts);
1type Todo = { 2 id: number; 3 title: string; 4 completed: boolean; 5 tags?: string[]; 6}; 7 8// 定义 DraftTodo 9// 定义 SanitizedTodo 10// 定义 FinalizedTodo 11 12// 测试代码 13 14// ✅ DraftTodo – title 必填,其余可选 15const draft1: DraftTodo = { title: "开始项目" }; 16const draft2: DraftTodo = { title: "买杂货", completed: false }; 17 18console.log("草稿:", draft1, draft2); 19// const draftError: DraftTodo = { completed: true }; // ❌ 错误:缺少 title 20 21// ✅ SanitizedTodo – 不允许包含 id 22const sanitized: SanitizedTodo = { 23 title: "发布博客文章", 24 completed: true, 25 tags: ["写作"], 26}; 27 28console.log("清理后:", sanitized); 29// const sanitizedError: SanitizedTodo = { id: 1, title: "出错了", completed: true }; // ❌ 错误:不应存在 id 30 31// ✅ FinalizedTodo – 所有字段必填,包括 tags 32const final: FinalizedTodo = { 33 id: 1, 34 title: "提交 PR", 35 completed: true, 36 tags: ["代码", "评审"], 37}; 38 39console.log("最终版:", final); 40// const finalError: FinalizedTodo = { id: 2, title: "差不多了", completed: true }; // ❌ 错误:缺少 tags

提示

  • 使用 Omit<T, K> 从类型中移除指定字段。
  • 使用 Partial<T> 将类型的所有字段变为可选。
  • 使用 Pick<T, K> 提取所需字段并确保其存在。
  • 使用 & 操作符合并类型,精确控制哪些字段是必需的、哪些是可选的。

解决方案:组合工具类型以建模 Todo 的各种变体

1type Todo = { 2 id: number; 3 title: string; 4 completed: boolean; 5 tags?: string[]; 6}; 7 8type DraftTodo = Partial<Omit<Todo, "title">> & Pick<Todo, "title">; 9type SanitizedTodo = Omit<Todo, "id">; 10type FinalizedTodo = Required<Todo>; 11 12// 测试代码 13 14// ✅ DraftTodo – title 必填,其余可选 15const draft1: DraftTodo = { title: "开始项目" }; 16const draft2: DraftTodo = { title: "买杂货", completed: false }; 17 18console.log("草稿:", draft1, draft2); 19// const draftError: DraftTodo = { completed: true }; // ❌ 错误:缺少 title 20 21// ✅ SanitizedTodo – 不允许包含 id 22const sanitized: SanitizedTodo = { 23 title: "发布博客文章", 24 completed: true, 25 tags: ["写作"], 26}; 27 28console.log("清理后:", sanitized); 29// const sanitizedError: SanitizedTodo = { id: 1, title: "出错了", completed: true }; // ❌ 错误:不应存在 id 30 31// ✅ FinalizedTodo – 所有字段必填,包括 tags 32const final: FinalizedTodo = { 33 id: 1, 34 title: "提交 PR", 35 completed: true, 36 tags: ["代码", "评审"], 37}; 38 39console.log("最终版:", final); 40// const finalError: FinalizedTodo = { id: 2, title: "差不多了", completed: true }; // ❌ 错误:缺少 tags

说明:

  • 第 8 行:DraftTodo 组合多个工具类型,使得除 title 外所有字段都可选:

    • Omit<Todo, "title"> 移除 title 字段;
    • Partial<...> 将剩余字段设为可选;
    • Pick<Todo, "title"> 重新引入 title 并设为必填;
    • 使用 & 将两部分合并,得到仅 title 必填的类型。
  • 第 9 行:SanitizedTodo 使用 Omit 移除内部使用的 id 字段,用于安全地对外暴露数据。

  • 第 10 行:FinalizedTodo 使用 Required 确保所有字段(包括原本可选的 tags)都必须提供。

类与泛型

类型关系:keyof、索引访问和 typeof