[Day18] TS:理解 Omit 的实作

Omit

是我们今天要聊的内容,老样的,如果你已经可以轻松看懂,欢迎直接左转去看同事 Ken 精彩的文章 — 「From State Machine to XState」。

昨天我们说明到在 TypeScript 中内建的 Utility Type Pick 可以帮助开发者从物件型别中挑出想要的属性,以次建立出新的型别:

type Person = {
  firstName: string;
  lastName: string;
  age: number;
};

type PersonName = Pick<Person, 'firstName' | 'lastName'>;

今天我们继续延续这个例子的使用,但是要把它的功能反过来,也就是说 Pick 是挑出想要的元素,现在则来写一个 Omit,让它是从物件型别中剔除不想要的属性。

先从 Mapped Types 的角度思考可以怎麽写:

type Person = {
  firstName: string;
  lastName: string;
  age: number;
};

type PersonName = {
  [P in keyof P]: Person[P];
}

一开始 Mapped Types 可以写成这样,但这样就是最单纯的复制一个物件型别的意思。

接着从所有的属性 Key 中剔除 age 的属性,变成:

type PersonName = {
  [P in Exclude<keyof Person, 'age'>]: Person[P];
};

这里使用 Day09 是提过的 Exclude,而 Exclude<keyof Person, 'age'> 在这里就等同於 'firstName' | 'lastName'。写到这里,出来的型别其实就已经符合想要的结果:

Omit

在完成了预期的功能後,接着来看看能不能让它变成一个更泛用的 Utility Type。首先,把带入的物件型别 Person 变成一个可以带入的泛型 T

// 把原本直接使用的 `Person` 变成参数 `T`
type ToPersonName<T> = {
  [P in Exclude<keyof T, 'age'>]: T[P];
};

再来把希望被剔除的参数也变成一个泛型参数 K

// 把原本直接使用的 'age' 变成参数 `K`
type ToPersonName<T, K> = {
  [P in Exclude<keyof T, K>]: T[P];
};

看起来已经相当泛用了,现在已经可以透过这个 Utility Type 从物件型别 T 中剔除掉不想要的属性 Keys K,到这里虽然可以结束了,但让我们回过头来看一下昨天写的 Pick<Type, Keys> 的原始码:

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

你有没有发现 ToPersonName 的整个轮廓其实和 Pick 非常接近:

Pick and Omit

也就是说,这里的 ToPersonName 其实只要用 Pick 就可以完成了,把原本的 ToPersonName 改用 Pick 来写:

// 把原本的 `ToPersonName` 改用 `Pick` 来写
type ToPersonName<T, K> = Pick<T, Exclude<keyof T, K>>;

江江~发现了吗,你已经写出和 TypeScript 官方提供的 Omit 差不多的原始码了。在原本的 Omit 中,为了确保 K 一定是可以被放入 Mapped Types 中使用的,所以有对 K 多加上了 extends keyof any 的泛型限制:

// Construct a type with the properties of T except for those in type K
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

从这两天的内容中,读者都可以发现,可以先根据实际的情况撰写出想要的结果後,再把可以抽成参数的部分变成泛型,最後变成一个更泛用的 Utility Types。

范例程序码

https://tsplay.dev/W4pqaW @ TypeScript Playground

参考资料

Omit @ TypeScript > References > Utility Types


<<:  冲刺之外的学习

>>:  Docker:KVM管理介面(virt-manager)

Day20:20 - 结帐服务(4) - PayPal Python Checkout SDK(2)

ನಮಸ್ಕಾರ,我是Charlie! 在Day19当中我们完成了Paypal的注册并且试着发了req...

Day-17 你在专案中负责什麽项目?遇到什麽困难?怎麽解决?

如果你有专案,有作品,通常一定会问你这类题目,而且你的回答很重要,千万要小心作答! 以我自身的例子...

Swift 新手-如何使用 Xcode 建立专案?

Xcode 版本 12.5 介面 点选 ios app 建立专案范本,范本有内建预设程序码,协助快速...

Day 27 - 资料视觉化与API - 将资料转化成艺术

前言 觉得这个文章,花了太多时间在写但有些设定好像应该 更把他分的更清楚而不是一直只丢范例出来解释。...

网页超连结-30天学会HTML+CSS,制作精美网站

超连结是建立网页与网页之间的关系,也可以连结到外部网站。a是Anchor的缩写,中文翻译为「锚」,点...