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
相关推荐
空中海2 小时前
01 React Native 基础、核心组件与布局体系
javascript·react native·react.js
前端之虎陈随易4 小时前
2年没用Nodejs了,Bun很香
linux·前端·javascript·vue.js·typescript
好运的阿财5 小时前
OpenClaw工具拆解之host_workspace_write+host_workspace_edit
前端·javascript·人工智能·机器学习·ai编程·openclaw·openclaw工具
XiYang-DING6 小时前
JavaScript
开发语言·javascript·ecmascript
空中海6 小时前
02 React Native状态、导航、数据流与设备能力
javascript·react native·react.js
空中海7 小时前
02 状态、Hooks、副作用与数据流
开发语言·javascript·ecmascript
空中海7 小时前
04 React Native工程化、质量、发布与生态选型
javascript·react native·react.js
杨超凡8 小时前
豆包收费了?我特么自己用“意念”搓了一个!
javascript
threelab9 小时前
Three.js 咖啡杯烟雾效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能