TS中有许多常用的工具类型映射类型,可以避免重复的类型定义。
在本文中,我们将ts的工具类型分为三类,分别是
- 对联合类型进行操作的(Exclude、Extract、NonNullable...)
- 对对象类型进行操作的(Partial、Pick、Omit...)
- 对函数类型进行操作的(ReturnType、Paramter...)
联合类型
1. Exclude<P,K>
Exclude接收两个范型P K,其中P是一个联合类型,K是P中的一个子类型,这个工具类型主要就是将P中的联合类型K给移除掉。
type TP = "foo" | "bar";
type TK = "bar";
type test = Exclude<TP, TK>; // "foo"
那我们如何实现一个自己的exclude呢,其实不难发现,exclude就是将P中的K给全部移除了,要实现这个,就需要我们用到ts中类型的分布式了。
type TP = "foo" | "bar";
type TK = "bar";
type MyExclude<P, K> = P extends K ? never : P;
type test = MyExclude<TP, TK>; // "foo"
其中把P分配给类型K进行比较,如果P是K的子类型,则返回never,如果不是则返回P 很容易发现,K是不受P约束的,就意味着TK中的字段不是TP的子类型也不会报错。 对此我们可以进一步对K进行约束。
type TP = "foo" | "bar";
type TK = "bar" | "oo";
type MyExclude<P, K extends P> = P extends K ? never : P;
type test = MyExclude<TP, TK>; //类型“TK”不满足约束“TP”,不能将类型“"oo"”分配给类型“TP”。
2. Exteact<P,K>
Extract接收两个范型P K,其中P是一个联合类型,K是P中的一个子类型,这个工具类型主要就是将P中的符合类型K的给提取出来。
type Person = {
name: string;
age: number;
gender: 'male' | 'female';
};
type test = Extract<keyof Person, "name">; // 'name'
Extract主要就是将联合类型中指定的key给提取出来。所以我们可以很轻松实现。
type Person = {
name: string; // 将类型改为string
age: number;
gender: 'male' | 'female';
};
type MyExtract<P,K> = P extends K ? P : never
type test = MyExtract<keyof Person, "name">; // "name"
同理我们也可使用范型约束K的入参
type Person = {
name: string; // 将类型改为string
age: number;
gender: 'male' | 'female';
};
type MyExtract<P,K extends P> = P extends K ? P : never
type StringProps = MyExtract<keyof Person, "foo">; // Type '"foo"' does not satisfy the constraint 'keyof Person
3. NonNullable<T>
NonNullable 作用是从类型 T 中去除 null 和 undefined 类型,返回一个新的类型,即 T 类型中所有非 null 和 undefined 的类型。
type NullableString = string | null | undefined;
type NonNullableString = NonNullable<NullableString>; // string
那我们要实现一个NonNullable也非常简单了,同样也是用到了分布式,将undefined 以及null 从T中剔除掉即可。
type NullableString = string | null | undefined;
type MyNullableString<T> = T extends null|undefined ? never : T
type NonNullableString = MyNullableString<NullableString>; // string
对象类型
1.Partial<T>
它的作用是将类型 T 中所有属性变为可选属性,即将每个属性的类型从 T[K] 变为 T[K] | undefined。
interface Person {
name: string;
age: number;
gender: 'male' | 'female';
}
type PartialPerson = Partial<Person>;
// 等价于
// type PartialPerson = {
// name?: string | undefined;
// age?: number | undefined;
// gender?: "male" | "female" | undefined;
// }
实现一个自己的Partial,只需遍历对象中的每一个字段,并将它改为可选就行了。
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
2.Pick<T,K>
它的作用是从类型 T 中选择指定的属性 K,返回一个新的类型,即只包含 T 类型中指定属性的子类型。
interface Person {
name: string;
age: number;
gender: 'male' | 'female';
}
type PersonNameAndAge = Pick<Person, 'name' | 'age'>;
// 等价于
// type PersonNameAndAge = {
// name: string;
// age: number;
// }
实现自己的一个Pick,只需要遍历K中每一个元素并且从T中取出该元素对应的类型返回就行了,如果是则返回该元素,不是则返回never就行了。
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
3.Omit<T,K>
....