TypeScript实用类型之Omit

概述

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,那么我们就需要在UserNewUser两个类型中都添加这个属性,维护起来非常麻烦,删除某个属性也面临同样的问题。

有没有更好的办法呢?这时候,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类型就会同时排除idemail属性。

写到这里,似乎该结束了,但是作为一个有追求的程序员,你以为这就完了吗?当然不行,我们要举一反三,如果反过来该怎么办呢?

向类型中添加属性

假设你维护的是一个老系统,原来的代码先定义了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知识分享。

参考

  1. https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys
相关推荐
codingandsleeping3 小时前
重读《你不知道的JavaScript》(上)- 作用域和闭包
前端·javascript
烛阴5 小时前
Puppeteer入门指南:掌控浏览器,开启自动化新时代
前端·javascript
芝士加7 小时前
Playwright vs MidScene:自动化工具“双雄”谁更适合你?
前端·javascript
Carlos_sam8 小时前
OpenLayers:封装一个自定义罗盘控件
前端·javascript
前端南玖9 小时前
深入Vue3响应式:手写实现reactive与ref
前端·javascript·vue.js
Yueyanc10 小时前
LobeHub桌面应用的IPC通信方案解析
前端·javascript
麦当_11 小时前
基于 Shadcn 的可配置表单解决方案
前端·javascript·面试
Cutey91611 小时前
使用Canvas实现实时视频处理:从黑白滤镜到高级特效
前端·javascript
前端大卫11 小时前
前端调试太痛苦?这 6 个技巧直接解决 90% 问题!
前端·javascript