TypeScript 工具类型
TS 内置了一批"工具类型"(Utility Types),它们是对类型进行变换的函数——传入一个类型,返回一个新类型。日常开发中,Partial、Pick、Omit、Record 这几个几乎天天用。这一章把最高频的几个讲透。
1. Partial / Required / Readonly
这三个最简单:Partial<T> 把 T 的所有属性变可选,Required<T> 全变必填,Readonly<T> 全变只读。其中 Partial 用得最多——做"部分更新"时简直是标配:
// Partial<T>:把 T 的所有属性变成可选
interface User {
id: number;
name: string;
age: number;
}
// 更新用户信息时,通常只传部分字段
function updateUser(id: number, patch: Partial<User>): void {
// patch 的每个属性都是可选的
console.log(`更新用户 ${id}`, patch);
}
updateUser(1, { name: "新名字" }); // ✅ 只传 name
updateUser(2, { name: "a", age: 21 }); // ✅ 传部分
// updateUser(3, { extra: 1 }); // ❌ extra 不在 User 里
// 相关:Required<T> 全部变必填;Readonly<T> 全部变只读
type RequiredUser = Required<User>;
type ReadonlyUser = Readonly<User>;2. Pick / Omit(挑选与排除)
这俩互为反面:Pick<T, K> 从 T 里挑几个字段,Omit<T, K> 从 T 里排除几个字段。它们是"复用已有类型派生新类型"的核心工具:
// Pick<T, Keys>:从 T 里挑几个字段
interface Article {
title: string;
content: string;
author: string;
tags: string[];
}
type ArticlePreview = Pick<Article, "title" | "author">;
// 等价于 { title: string; author: string }
const preview: ArticlePreview = {
title: "标题",
author: "小明",
};
// Omit<T, Keys>:从 T 里排除几个字段(和 Pick 相反)
type CreateArticleDTO = Omit<Article, "author">;
// 等价于 { title: string; content: string; tags: string[] }
// Pick 挑选,Omit 排除,二者互补3. Record(构造键值对类型)
Record<K, V> 构造一个"键类型为 K、值类型为 V"的对象类型。它非常适合描述映射表、配置表、权限表:
// Record<K, V>:构造一个"键为 K、值为 V"的对象类型
type Role = "admin" | "editor" | "viewer";
// 角色对应的权限列表
const permissions: Record<Role, string[]> = {
admin: ["read", "write", "delete"],
editor: ["read", "write"],
viewer: ["read"],
};
// 常用于"映射表/配置表"
const labelMap: Record<number, string> = {
1: "待处理",
2: "进行中",
3: "已完成",
};Record 配合字面量联合类型(如 Role),TS 会强制你为每个键都提供值,漏一个就报错——非常安全。
4. ReturnType / Parameters(提取函数信息)
这俩从已有的函数提取返回值类型或参数类型,避免重复定义。在复用第三方函数的类型时特别有用:
// ReturnType<T>:取函数 T 的返回值类型
function getUser() {
return { id: 1, name: "小明" };
}
type User = ReturnType<typeof getUser>;
// 等价于 { id: number; name: string }
// Parameters<T>:取函数的参数类型(元组)
function add(a: number, b: string): void {}
type AddArgs = Parameters<typeof add>; // [number, string]
// 这两个在写"复用函数返回值/参数类型"时极其常用5. 实战:从后端模型派生表单类型
把工具类型组合起来,解决一个真实问题:一个完整的产品模型,怎么派生出"创建表单"和"更新表单"两种类型?
// 实战:把后端返回的"完整模型"变成"创建表单"的 DTO
interface Product {
id: number; // 后端生成,创建时不传
name: string;
price: number;
createdAt: string; // 后端生成
updatedAt: string; // 后端生成
}
// 创建产品的表单只需要用户能填的字段
type ProductForm = Omit<Product, "id" | "createdAt" | "updatedAt">;
// 等价于 { name: string; price: number }
// 编辑产品的表单:所有字段都可选
type ProductPatch = Partial<ProductForm>;
function create(p: ProductForm): void { /* ... */ }
function update(id: number, p: ProductPatch): void { /* ... */ }这种"从单一数据源派生多种类型"的写法,是 TS 工程化的精髓——改一处 Product,所有派生类型自动更新,绝不重复定义。
6. 其他常用工具类型
除了上面几个,TS 还内置了这些(不细讲,知道有就行):
Exclude<T, U>/Extract<T, U>:从联合类型里排除/提取。NonNullable<T>:排除 null 和 undefined。Awaited<T>:递归解开 Promise,取最终类型。keyof T:取 T 的所有键的联合(操作符,不是工具类型,但常配合使用)。
小结
工具类型是"对类型做变换的函数"。最该记牢的是这五个:Partial(全可选)、Pick(挑字段)、Omit(排除字段)、Record(键值对)、ReturnType(取返回值)。它们让你能从已有类型派生新类型,避免重复定义。下一篇讲类型断言与类型守卫。
← 上一篇 TypeScript 模块
下一篇 TypeScript 类型断言与守卫 →