一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
TS中提供了一些我们平常开发中可以频繁使用的工具类型,如将一个接口类型中的属性全部设置为只读类型,我们不可以每次还要写一堆keyof in等映射对象类型和索引类型组合的类型来实现此功能,所以TS提供了一些,当然我们也可以自己定义一些其他的TS没有内置的,但是在项目中经常会遇到的。 这里我们就将内置的工具都介绍一下,并结合它们是如何实现的,来提升我们对TS中提供的类型和它们的混合使用的理解和加深。
Partial<T>
能将T类型中的所有属性变成可选属性。
type Person = { name: string, age: string };
type NewPerson = Partial<Person>;
// 相当于将Person变成了如下类型
type NewPerson = { name?: string, age?: string };
Partial的源代码如下
type Partial<T> = {
[K in keyof T]?: T[K];
}
通过索引类型查询keyof获取类型T的所有属性的联合类型,再创建映射类型对象,通过in将此联合类型进行变量,将每个属性K加上可选符号?,并通过索引访问类型访问T中和K一样属性名的属性类型,赋值给K属性, 就实现了此工具类型。
Required<T>
和Partial<T>刚好相反,将T类型中的所有属性变成必选属性。
type Person = { name?: string, age?: string };
type NewPerson = Required<Person>;
// 相当于将Person变成了如下类型
type NewPerson = { name: string, age: string };
Required<T>的源代码如下
type Required<T> = {
[K in keyof T]-?: T[K];
}
通过索引类型查询keyof获取类型T的所有属性的联合类型,再创建映射类型对象,通过in将此联合类型进行变量,将每个属性K都减去可选符号-?,并通过索引访问类型访问T中和K一样属性名的属性类型,赋值给K属性, 就实现了此工具类型,为什么减去是因为采用的是同态映射对象会将修饰符和可选符好带来数以要减去。
Readonly<T>
将T类型中的所有属性变成只读属性。
type Person = { name?: string, age?: string };
type NewPerson = Required<Person>;
// 相当于将Person变成了如下类型
type NewPerson = { readonly name?: string, readonly age?: string };
Readonly<T>的源代码如下
type Readonly<T> = {
readonly [K in keyof T]: T[K];
}
和Required语法一样只是加了一个readonly,可以参照Required的解释。
Record<K, T>
将T类型付给K中的每个属性上组成一个对象类型。
type Person = { name?: string, age?: string };
type Keys = 'xiaoming' | 'wangsan';
type NewPerson = Record<Keys, Person>;
// 相当于将Person变成了如下类型
type NewPerson1 = {
xiaoming: { name?: string, age?: string },
wangsan: { name?: string, age?: string }
};
Record<K, T>的源代码如下
type Record<K extends keyof any, T> = {
[P in K]: T;
};
K extends keyof any 表示约束K是只能是联合类型string | number | symbol中的子类型也就是K也是一个联合类型, 通过同态映射对象类型将K中的每个子类型进行遍历成为对象属性名类型,并将T赋值给该属性名类型作为对应的值类型。
Exclude<T,U>
如果T是U的子类型就返回never类型,一般用于将去除联合类型(U)中的某些子类型(T)
type T = Exclude<number | string, number>;
// 等于
type U = string;
Exclude<T,U>的源代码如下
type Exclude<T, U> = T extends U ? never : T;
通过条件类型判断T如果是U的子类型就返回never类型否则返回T类型,当T类型是联合类型的情况时,会将判断T类型中的每个子类型分别判断是否是U类型的子类型返回never或者该子类型,并通过联合类型符号进行联合,如果某个新的子类型判断结果返回的时never联合类型就会自动过滤掉nerver,此过程就叫做分布式条件类型。
Extract<T,U>
如果T是U的子类型就返回U类型,一般用于将保留联合类型(U)中的某些类型(T)
type T = Extract<number | string, number>;
// 等于
type U = number;
Extract<T,U>的源代码如下
type Extract<T, U> = T extends U ? T : never;
和Exclude<T,U>刚好相反就不解释了。
NonNullable<T>
去除联合类型中的null和undefined类型。
type T = NonNullable<number | null | undefined>;
// 等于
type U = number;
NonNullable<T>的源代码如下
type NonNullable<T> = T extends null | undefined ? never : T;
NonNullable只能作用于联合类型,通过分布式条件类型判断T类型中的每个子类型是否是null | undefined的子类型如果是返回never否则返回该子类型生成一个新的联合类型,联合类型自动会去除never类型。
Pick<T,K>
保留对象类型T中几个属性名类型(K 联合类型)其他属性名删除掉生成一个新的对象类型
type Person = { name?: string, age?: string, tel: string };
type Keys = 'name' | 'tel';
type NewPerson = Pick<Person, Keys>;
// 相当于将Person变成了如下类型
type NewPerson1 = { name?: string, tel: string }
Pick<T,K>的源代码如下
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
K extends keyof T 通过索引类型查询查询T中的所有属性名的联合类型,并约束K只能是该联合类型的子类型, 通过同态映射对象类型遍历K联合类型作为生成的新的对象类型的属性名类型,该属性的值类型为T中对应属性名的类型。
Omit<T,K>
和Pick刚好相反,保留T类型中的属性名类型不是K联合类型中的子类型的属性名类型,返回一个新的对象类型。
type Person = { name?: string, age?: string, tel: string };
type Keys = 'name' | 'tel';
type NewPerson = Omit<Person, Keys>;
// 相当于将Person变成了如下类型
type NewPerson1 = { age?: string }
Omit<T,K>的源代码如下
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
K extends keyof any 表示K只能是联合类型string | number | symbol中的子类型, keyof T获取T中的所有属性名类型组件的联合类型, Exclude<keyof T, K>表示去除T中属性名是K的子类型的属性名,返回一个包含K的或有属性名,用Pick类型工具保留T中不是K的属性。