在 TypeScript 项目中,我们经常会遇到一个问题:
一个对象有很多字段,但是不同业务场景需要的字段并不一样。
例如用户模型:
interface User {
id: number;
name: string;
age: number;
email: string;
password: string;
}
完整的 User 包含:
User
|
|-- id
|-- name
|-- age
|-- email
|-- password
但是实际开发中:
- 用户列表只需要 id 和 name
- 注册页面只需要 name 和 password
- 用户详情不能返回 password
- 修改用户时只修改部分字段
如果每个地方都重新定义接口:
interface UserCard {
id:number;
name:string;
}
interface UserDetail {
id:number;
name:string;
email:string;
}
会出现一个问题:
如果 User 修改了字段:
name -> username
那么所有依赖 User 的接口都需要手动修改。
大型项目中,这会导致:
- 类型重复
- 字段不一致
- 修改困难
所以 TypeScript 提供了工具类型(Utility Types),让我们可以基于已有类型生成新的类型。
1. Pick:从类型中挑选字段
什么是 Pick?
Pick 的作用:
从一个已有类型中选择指定字段,生成新的类型。
语法:
Pick<类型, 字段>
例如:
type UserPreview = Pick<User, 'id' | 'name'>;
表示:
从 User 中选择:
- id
- name
生成:
type UserPreview = {
id:number;
name:string;
}
等价于:
interface UserPreview {
id:number;
name:string;
}
使用:
const user: UserPreview = {
id:1,
name:"张三"
}
正确。
但是:
const user: UserPreview = {
id:1,
name:"张三",
age:18
}
会报错。
因为:
UserPreview 不包含 age
Pick 的实际应用
例如用户卡片:
页面只需要:
用户名
头像
那么:
type UserCard = Pick<User, 'name' | 'avatar'>
不用重新定义接口。
2. Omit:排除字段
什么是 Omit?
Omit 和 Pick 相反:
从已有类型中删除指定字段。
语法:
Omit<类型, 字段>
例如:
type UserWithoutPassword = Omit<User,'password'>
表示:
保留 User 的所有字段:
但是删除:
password
结果:
{
id:number;
name:string;
age:number;
email:string;
}
实际应用:隐藏敏感数据
数据库中的用户:
interface User {
id:number;
name:string;
password:string;
}
但是返回给前端:
不能包含:
password
所以:
type UserResponse = Omit<User,'password'>
避免密码泄露。
3. Partial:字段全部变成可选
什么是 Partial?
Partial 的作用:
将一个类型中的所有字段变成可选。
例如:
interface User {
id:number;
name:string;
email:string;
}
正常情况下:
const user:User = {
id:1,
name:"张三",
email:"xxx@qq.com"
}
所有字段必须存在。
但是修改用户资料时:
用户可能只修改名字:
{
"name":"李四"
}
这时候:
type UpdateUser = Partial<User>
得到:
{
id?:number;
name?:string;
email?:string;
}
? 表示:
这个字段可以不存在。
所以:
const update:UpdateUser = {
name:"李四"
}
合法。
4. Required:字段全部变成必填
Required 和 Partial 相反。
作用:
将可选字段变成必填字段。
例如:
interface Config {
theme?:string;
language?:string;
}
原本:
const config = {
theme:"dark"
}
合法。
使用:
type CompleteConfig = Required<Config>
变成:
{
theme:string;
language:string;
}
现在:
const config:CompleteConfig = {
theme:"dark"
}
错误。
因为:
缺少 language。
四个工具类型对比
| 工具类型 | 作用 | 示例 |
|---|---|---|
| Pick | 选择字段 | Pick<User,'id'> |
| Omit | 删除字段 | Omit<User,'password'> |
| Partial | 全部可选 | Partial<User> |
| Required | 全部必填 | Required<User> |
工程中的核心思想
不要:
复制接口
复制字段
重复维护
而应该:
User
|
----------------
| | |
Pick Omit Partial
| | |
页面 API 表单
维护一个核心类型,然后根据业务需求组合新的类型。
总结
TypeScript 工具类型解决的是:
如何根据已有类型快速创建新的类型。
其中:
- Pick:我要哪些字段
- Omit:不要哪些字段
- Partial:字段可以没有
- Required:字段必须存在
在 React + TypeScript 项目中,这些工具类型大量用于:
- API 数据类型定义
- 表单类型定义
- 页面展示类型定义
- 数据传递类型约束
掌握这些工具类型,可以让大型项目中的类型维护更加稳定。