TypeScript实用类型之Omit
概述
TypeScript Utility Types(实用工具类)包含一系列预定义的类型,用于简化类型操作,善用这些类型可以让我们的代码更加简洁优雅,今天来学习一下Omit类型。Omit类型可以优雅的解决类型重复问题,避免冗余代码。
Omit类型的作用是什么?与以往不同,我们先不介绍晦涩难懂的概念,而是从一个实际的例子出发,进而引出这个类型。
从类型中排除属性
考虑下面这个常见的场景,你正在开发一个用户管理系统,这个系统的一个重要功能就是管理用户,比如创建用户,更新用户信息,删除用户等。
为了支持以上操作,我们首先要定义一个用户类型User,下面就是这个User类型的定义:其中包括用户id,姓名,手机号和邮箱。
interface User {
id: number; // 用户ID
name: string; // 用户名
phone: string; // 手机号
email: string; // 邮箱
}
首先:我们编写创建用户的函数,这个函数需要接收一个User类型的参数,并调用后端API来创建用户。
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来更新用户信息。
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类型。
interface NewUser {
name: string;
phone: string;
email: string;
}
但是,这样做有一个问题, NewUser类型和User类型几乎一模一样,除了id属性外,其他字段都是重复的,这就是典型的冗余代码,对于日后的维护十分不便。
设想一下,假如某一天需要为用户添加一个新的属性,比如address,那么我们就需要在User和NewUser两个类型中都添加这个属性,维护起来非常麻烦,删除某个属性也面临同样的问题。
有没有更好的办法呢?这时候,Omit类型就派上用场了,Omit类型允许我们从一个类型中排除某些属性,从而创建一个新的类型。
下面这段代码表示:创建一个新类型NewUser,它是从User类型中排除掉id属性后的结果。
type NewUser = Omit<User, 'id'>;
现在,我们可以使用NewUser类型来创建用户了。
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属性,可以这样写:
type NewUser = Omit<User, 'id' | 'email'>;
这样,NewUser类型就会同时排除id和email属性。
写到这里,似乎该结束了,但是作为一个有追求的程序员,你以为这就完了吗?当然不行,我们要举一反三,如果反过来该怎么办呢?
向类型中添加属性
假设你维护的是一个老系统,原来的代码先定义了NewUser类型(只有创建用户的需求),现在添加了一个新需求:要求添加一个函数用于更新用户的信息,更新用户信息就需要提供用户ID,这时候你需要一个新的类型,也就是在NewUser的基础上添加id属性。通俗点说,前面的例子是在一个类型中排除某些属性,而现在我们需要在一个类型中添加某些属性。这相当于Omit的反向操作。
那TypeScript中有没有这样的实用类型呢?非常遗憾,TypeScript的标准库中并没有提供这样的类型,但是我们可以自己实现一个。
下面的代码使用&操作符来创建一个新的类型UpdateUser,它包含了NewUser的所有属性,并添加了一个id属性。
type UpdateUser = NewUser & { id: number };
这样,我们就可以使用UpdateUser类型来更新用户信息了。
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知识分享。
参考
TypeScript实用类型之Omit的更多相关文章
- 编写TypeScript工具类型,你需要知道的知识
什么是工具类型 用 JavaScript 编写中大型程序是离不开 lodash 工具的,而用 TypeScript 编程同样离不开工具类型的帮助,工具类型就是类型版的 lodash .简单的来说,就是 ...
- TypeScript 条件类型精读与实践
在大多数程序中,我们必须根据输入做出决策.TypeScript 也不例外,使用条件类型可以描述输入类型与输出类型之间的关系. 本文同步首发在个人博客中,欢迎订阅.交流. 用于条件判断时的 extend ...
- C# vs TypeScript - 高级类型
总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ...
- 从C#到TypeScript - 高级类型
C# vs TypeScript - 高级类型 上一篇讲了基础类型,基本上用基础类型足够开发了,不过如果要更高效的开发,还是要看下高级类型,这篇和C#共同点并不多,只是延用这个主题. 联合类型 可以从 ...
- TypeScript 之类型判断
在使用 Angular 做项目的时候,对 TypeScript 的类型判断不太熟练,为了方便查找,特意对 TypeScript 的类型判断做了简单梳理.文章只是 TS 官网的内容摘要,没有高深的知识, ...
- TypeScript的类型
⒈TypeScript的类型 JavaScript语言的数据类型包括以下7种: 1.boolean(布尔),true || false 2.null,表明null值得特殊关键字,JavaScript是 ...
- TypeScript入门三:TypeScript函数类型
TypeScript函数类型 TypeScript函数的参数 TypeScript函数的this与箭头函数 TypeScript函数重载 一.TypeScript函数类型 在上一篇博客中已经对声明Ty ...
- React 与 Hooks 如何使用 TypeScript 书写类型?
React 与 Hooks 如何使用 TypeScript 书写类型? 本文写于 2020 年 9 月 20 日 函数组件与 TS 对于 Hooks 来说是不支持使用 class 组件的. 如何在函数 ...
- TypeScript 高级类型
⒈交叉类型(Intersection Types) 交叉类型是将多个类型合并为一个类型. 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性. 例如, Person &a ...
- Typescript基础类型
1.布尔值__boolean 2.数字__number----除了支持十进制和十六进制字面量,Typescript还支持ECMAScript 2015中引入的二进制和八进制字面量. 3.字符串__st ...
随机推荐
- Django实战项目-学习任务系统-定时任务管理
接着上期代码框架,开发第4个功能,定时任务管理,再增加一个学习定时任务表,主要用来设置周期重复性的学习任务,定时周期,定时时间,任务标题和内容,预计完成天数,奖励积分和任务状态等信息. 现实中学习一门 ...
- pycharm-pip安装scrapy、pywifi等模块报错解决方法
之前学Python时,使用pycharm安装一些不常用的模块时,报错,安装不成功.找了很多方法,总算好了,总结一下: 一.大部分安装不成功的原因,都是原因pip安装源地址问题. 1.在项目pip.ex ...
- 活动中台系统慢 SQL 治理实践
作者:vivo 互联网服务器团队- Zhang Mengtao 活动中台系统作为中台项目非常注重系统性能和用户体验,数据库系统性能问题会对应用程序的性能和用户体验产生负面影响.慢查询可能导致应用程序响 ...
- 自动驾驶 | 为CarLA添加一辆小米SU7 Part I
自动驾驶 | 为CarLA添加一辆小米SU7 Part I 导言 什么是CarLA? CarLA是一款基于虚幻引擎4(Unreal Engine 4)构建的开源自动驾驶仿真平台,为自动驾驶算法的研发. ...
- Transformer(自然语言处理)笔记
Transerformer架构(自然语言处理) 尝试学习和从零构建一个大语言模型 就目前我的认知 Transformer架构主要分为编码器.解码器.词表.训练集.训练算法(T5) 编码器(Encode ...
- Python简单数据分析
1.分析思路 以贵族价格表为例 a.使用Python连接MySQL数据库 b.从noble_right表查询贵族名称,开通价格 c.将这两组值作为XY轴绘制直方图 2.编写代码: # -*- codi ...
- python爬虫爬取B站视频字幕,词频统计,使用pyecharts画词云(wordcloud)
我们使用beatifulsop爬取到B站视频的字幕:https://www.cnblogs.com/becks/p/14540355.html 然后将爬取的字幕,使用pandas处理后写到CSV文件中 ...
- Robot Framework全局变量集合取值
在一次测试中,可能需要使用多个不同的会员,即需要多注册多个会员.如此配置单一参数化是无法满足对所有注册会员名的统一管理,这里引入参数变量组来实现 步骤如下: 1.脚本目录点击总目录,右键点击New R ...
- eolinker请求预处理:配置全局环境变量后,步骤内去掉请求头信息
特别注意:需要使用全局变量或者预处理前务必阅读本链接https://www.cnblogs.com/becks/p/13713278.html 1.描述,用例配置环境变量后会在请求前自动加上域名和请求 ...
- 康谋分享 | aiSim5仿真场景重建感知置信度评估(三)
aiSim5重建高精度的真实交通场景,用于测试和训练ADAS/AD系统.内置场景包括赛道.车库.高速公路和城市环境.通过全局行动日志,aiSim能将驾驶数据转化为场景重建.车道线检测算法在仿真与现实世 ...