概述
TypeScript Utility Types
(实用工具类)包含一系列预定义的类型,用于简化类型操作,善用这些类型可以让我们的代码更加简洁优雅,今天来学习一下Omit
类型。Omit
类型可以优雅的解决类型重复问题,避免冗余代码。
Omit
类型的作用是什么?与以往不同,我们先不介绍晦涩难懂的概念,而是从一个实际的例子出发,进而引出这个类型。
从类型中排除属性
考虑下面这个常见的场景,你正在开发一个用户管理系统,这个系统的一个重要功能就是管理用户,比如创建用户,更新用户信息,删除用户等。
为了支持以上操作,我们首先要定义一个用户类型User
,下面就是这个User
类型的定义:其中包括用户id,姓名,手机号和邮箱。
typescript
interface User {
id: number; // 用户ID
name: string; // 用户名
phone: string; // 手机号
email: string; // 邮箱
}
首先:我们编写创建用户的函数,这个函数需要接收一个User
类型的参数,并调用后端API来创建用户。
typescript
function createUser(user: User) {
// 调用后端API来创建用户
api.createUser(user).then(response => {
console.log('User created:', response.data);
}).catch(error => {
console.error('Error creating user:', error);
});
}
接下来,我们编写更新用户信息的函数,这个函数需要接收一个User
类型的参数,并调用后端API来更新用户信息。
typescript
function updateUser(user: User) {
// 调用后端API来更新用户信息
api.updateUser(user).then(response => {
console.log('User updated:', response.data);
}).catch(error => {
console.error('Error updating user:', error);
});
}
删除用户的函数我们就不写了,因为它不影响我们今天的主题。
到现在为止,似乎一切都很顺利,创建用户和更新用户的函数使用同一个User
类型,代码也很简洁。
但是,这里有一个小问题,那就是在创建用户的时候,其实我们并不需要提供用户的id
,因为只有用户创建成功之后才会生成这个id。虽然说多传一个id
属性不会报错,但是从逻辑上来说,这个id
属性是多余的。作为一个有追求的程序员,不能容忍这种冗余代码的存在。
于是有的同学说:这还不简单吗?再定一个类型用于创建用户,把id
属性去掉不就行了?于是就有了下面的NewUser
类型。
typescript
interface NewUser {
name: string;
phone: string;
email: string;
}
但是,这样做有一个问题, NewUser
类型和User
类型几乎一模一样,除了id
属性外,其他字段都是重复的,这就是典型的冗余代码,对于日后的维护十分不便。
设想一下,假如某一天需要为用户添加一个新的属性,比如address
,那么我们就需要在User
和NewUser
两个类型中都添加这个属性,维护起来非常麻烦,删除某个属性也面临同样的问题。
有没有更好的办法呢?这时候,Omit
类型就派上用场了,Omit
类型允许我们从一个类型中排除某些属性,从而创建一个新的类型。
下面这段代码表示:创建一个新类型NewUser
,它是从User
类型中排除掉id
属性后的结果。
typescript
type NewUser = Omit<User, 'id'>;
现在,我们可以使用NewUser
类型来创建用户了。
typescript
function createUser(user: NewUser) {
// 调用后端API来创建用户
api.createUser(user).then(response => {
console.log('User created:', response.data);
}).catch(error => {
console.error('Error creating user:', error);
});
}
如果某一天需要为用户添加一个新的属性,比如address
,我们只需要在User
类型中添加这个属性,而不需要修改NewUser
类型,这样就避免了冗余代码的出现。删除某个属性也同样方便。
更方便的是,Omit
一次可以排除多个属性,比如我们还想排除email
属性,可以这样写:
typescript
type NewUser = Omit<User, 'id' | 'email'>;
这样,NewUser
类型就会同时排除id
和email
属性。
写到这里,似乎该结束了,但是作为一个有追求的程序员,你以为这就完了吗?当然不行,我们要举一反三,如果反过来该怎么办呢?
向类型中添加属性
假设你维护的是一个老系统,原来的代码先定义了NewUser
类型(只有创建用户的需求),现在添加了一个新需求:要求添加一个函数用于更新用户的信息,更新用户信息就需要提供用户ID,这时候你需要一个新的类型,也就是在NewUser
的基础上添加id
属性。通俗点说,前面的例子是在一个类型中排除某些属性,而现在我们需要在一个类型中添加某些属性。这相当于Omit
的反向操作。
那TypeScript中有没有这样的实用类型呢?非常遗憾,TypeScript的标准库中并没有提供这样的类型,但是我们可以自己实现一个。
下面的代码使用&
操作符来创建一个新的类型UpdateUser
,它包含了NewUser
的所有属性,并添加了一个id
属性。
typescript
type UpdateUser = NewUser & { id: number };
这样,我们就可以使用UpdateUser
类型来更新用户信息了。
typescript
function updateUser(user: UpdateUser) {
// 调用后端API来更新用户信息
api.updateUser(user).then(response => {
console.log('User updated:', response.data);
}).catch(error => {
console.error('Error updating user:', error);
});
}
是不是很优雅呢?你学会了吗?学会了就点个关注吧,后续会有更多有趣的TypeScript
知识分享。