再也不用担心类型定义冗余了!使用Pick工具类型优化TS开发体验!
阅读时间约 5 分钟。
在为接口返回的数据编写类型定义时,你肯定遇到过这样的问题:为接口返回的数据定义了一个属性很多的对象类型,而业务中有些逻辑却只需要接口中的某几个字段。像这样的场景,我们需要再单独声明一个类型定义吗?有没有什么好的办法可以将需要的属性提取出来,而不是再重新声明一个新的类型定义呢?
答案是有的。TS 标准库中就有这么一个工具类型:Pick
。
通过本文的学习,你将彻底学会并掌握 Pick
的用法。同时,我们还会分析它的源码,带你窥见 TS 的高级类型,进而让你写出更加灵活、强大的类型定义。
让我们开始吧~
1. Pick
的作用和用法
Pick
是 TS 标准库中提供的一个工具类型(Utility Type),它用于从一个类型中挑选出一部分属性,然后将挑选出来的属性构造成一个新的类型。
比如我们要从 Person
类型中挑选出其中的 name
属性和 age
属性来构造一个新的类型:
interface Person {
name: string;
age: number;
address: string;
}
type PersonNameAndAge = Pick<Person, "name" | "age">;
PersonNameAndAge
类型等价于下面的类型定义:
interface PersonNameAndAge {
name: string;
age: number;
}
结合上面的示例我们不难发现,Pick
的第一个参数是要从中挑选属性的原始类型,第二个参数则是一个由第一个参数类型中的键组成的联合类型。
可以看到,新类型 PersonNameAndAge
的属性名和类型都与原始类型 Person 中对应的属性一致。
2. Pick
源码分析
下面是 Pick
的源码定义:
/**
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
源码中涉及到两个关键字 in
和 extends
,以及一个操作符 keyof
。关键字 in
和 操作符 keyof
在《原来Partial这么神!TS中的对象可选属性解决方案》一文中有细致的讲解,推荐你阅读一下。
extends
是 TS 中的一个关键字,用于表示类型约束,通常情况下用于泛型约束中。在类型参数中使用 extends
可以限制类型参数必须满足某些条件。
keyof T
表示 T
的所有属性名组成的联合类型,比如:
interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // "name" | "age"
源码中的关键字 in
则表示迭代联合类型 K
中的每个属性,因此,泛型 P
表示联合类型 K
中的每个元素。这些元素与泛型 T
中的成员属性保持一致。
而 K extends keyof T
就是限制 K
必须是 keyof T
的子集,也就是 K
中的每个属性都必须是 T
中的属性名之一。K extends keyof T
约束可以确保我们不能选择泛型 T
中不存在的属性名,从而保证了类型的安全性。比如下面的示例:
type PersonName = Pick<Person, "name">; // { name: string; }
// 编译错误:Property 'email' does not exist on type 'Person'
type PersonEmail = Pick<Person, "email">;
由此可见,Pick
的作用就是从一个类型中选出一组数据,进而形成一个新的类型。
3. 总结
TS 标准库为我们提供的 Pick
工具类型,能让我们方便的从一个大型类型中取出需要的属性,从而一定程度上避免冗余的类型定义和类型检查错误。不过,在使用 Pick
时有几点需要注意:
Pick
的第一个参数必须是一个对象类型,并且该类型应是一个拥有成员属性的对象类型。- 确保
Pick
第二个参数是一个联合类型,并且联合类型中的每个成员属性都必须存在于第一个对象类型中。还要保证它不是一个空的联合类型,否则在编译时会报错。
掌握 Pick
能让我们更加熟练的操作 TS 中的类型系统,从而提高代码的可读性和可维护性,能让我们编写出更加灵活的代码,而且还能减少许多重复的类型定义。
你、学废了嘛 ~
本文首发微信公众号码上花甲,欢迎关注。