TS提供了一系列常用的工具类型来满足日常开发需要。这些类型可以全局访问。
预置知识
在学习类型编程之前,你需要掌握这些知识:
keyof
获取类型的keys列表;
如果传入原始类型,则会自动将原始类型转成引用类型,返回其原型的属性的列表
typeof
获取传入变量的类型
区别于javascript:
- 在对原始类型调用时,基本于javascript表现一致,返回小写的原始类型值
- 在对引用类型调用时,会推断该引用类型的类型,并返回;而javascript只会返回'object'
in
x in y 可以用于判断y是否包含x;
[k in keyof T]这里也用来遍历类型T的Keys
infer
推断类型
泛型缩写
- T (Type), 任意类型
- K (Key), 一般指集合的属性
- P (Prop), 一般指集合的属性
- U (UnionType), 一般指联合类型
- R (ReturnType), 一般指函数返回值类型
- E (Element),一般指元素类型
Partial<T>
将传入类型的所有属性变为可选。返回传入的类型的所有子集。源码
源码实现
type Partial<T> = {
[K in keyof T]?: T[K]
}
使用示例
可用于更新数据的场景
interface IUser {
name: string
age: number,
gender: string
}
const user: IUser = {
name: 'hquestion',
age: 30,
gender: 'man'
}
const updateUser = (userPartial: Partial<IUser>) => {
return {...user, ...userPartial}
}
updateUser({name: 'Gigi'})
Readonly<T>
将传入的类型的所有属性变为只读。源码
源码实现
type Readonly<T> = {
readonly [K in keyof T]: T[K]
}
使用示例
IUser interface 参考上文
const user: Readonly<Partial<IUser>> = {
name: 'Jack'
}
// Error: TS2540: Cannot assign to 'name' because it is a read-only property
user.name = 'Jhon';
Record<K, T>
创建一个属性类型为K,值类型为T的类型集合。可以用于将一个类型映射到另一个类型。源码
源码实现
type Record<K extends keyof any, T> = {
[P in K]: T
}
使用示例
type studentNames = | 'Jack' | 'Jhon' | 'Jason';
const studentInfoMap: Record<studentNames, Partial<IUser>> = {
Jack: {name: 'Jack'},
Jhon: {name: 'Jhon'},
Jason: {name: 'Jason'},
};
// Error: TS2551: Property 'Jacky' does not exist on type 'Record >'. Did you mean 'Jack'?
studentInfoMap.Jacky = {name: 'Jacky'}
Pick<T, K>
从名称很容易了解到,这个工具类型是从集合中选取一些属性组成一个新的集合类型。即返回类型T的子集。源码
Partial也是返回类型的子集。区别与Partial,Pick可以通过传入指定的Keys,来生成包含特定属性的子集。
源码
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
使用示例
// 假设IMan接口只需要name和age属性
type IMan = Pick<IUser, | 'name' | 'age'>;
const man: IMan = {name: 'Someman', age: 10}
// Error: TS2339: Property 'gender' does not exist on type 'Pick '.
man.gender = 'male';
type IWoman = Partial<IUser>;
const woman: IWoman = {name: 'Somewoman', age: 20};
woman.gender = 'female'; // Success
Exclude<T, U>
从类型T中剔除部分类型。
因为Omit<T, K>里使用了Exclude, 所以提前介绍Exclude
源码
type Exclude<T, U> = T extends U ? never : T
使用示例
type BC = Exclude<'a' | 'b' | 'c', 'a'>;
// Error: TS2322: Type '"a"' is not assignable to type '"b" | "c"'.
const val: BC = 'a';
// Success
const val: BC = 'b';
Omit<T, K>
从类型T中移除部分属性。
源码
type Omit<T, K> = {
[P in Exclude<keyof T, K>]: T[P]
}
使用示例
type ISubUser = Omit<IUser, 'age' | 'gender'>
// Success
const subUser: ISubUser = {name: 'subUser'}
// Error: TS2339: Property 'age' does not exist on type 'Pick '.
subUser.age = 20;
Extract<T, U>
提取。提取同时属于T和U的子集类型,即取两者的交集。
与Exclude<T, U>正好相反
源码
type Extract<T, U> = T extends U ? T : never;
使用示例
type A = 'a' | 'b' | 'c'
type B = 'b' | 'd' | 'e'
type AJoinB = Extract<A, B>
// Error: TS2322: Type '"d"' is not assignable to type '"b"'.
const val: AJoinB = 'd';
// Success
const val: AJoinB = 'b';
NonNullable<T>
从类型T上剔除null和undefined。
源码
type NonNullable<T> = T extends undefined | null ? never : T
使用示例
const user3: NonNullable<IUser> = {
name: 'xx',
age: 20,
// Error
gender: undefined,
}
Parameters<T>
从函数的参数列表生成一个参数列表类型元组的类型。
源码
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any? P : never
使用示例
type fnA = (name: string, age: number) => void
// 将得到:type Atype = [string, number]
type AType = Parameters<fnA>;
// Error: TS2322: Type 'string' is not assignable to type 'number'.
const atype: AType = ['name', 'age']
ConstructorParameters<T>
从构造函数的参数列表生成参数列表元组类型,使用上与Parameters<T>类似,不再赘述。
源码
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any? P : never
ReturnType<T>
从函数的返回值类型生成一个新的类型。
源码
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
使用示例
type fn = () => string
// 从这个简单的例子,我们一眼可以知道下面类型即:type FnReturn = string
type FnReturn = ReturnType<fn>
const fnReturnVal: FnReturn = '1';
InstanceType<T>
生成构造函数返回值类型的类型。如果传入的不是一个构造函数,即返回any
源码
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any
Required<T>
与Partial相反,将T类型的所有属性都设置为必填。
源码
type Required<T> = {
[K in keyof T]-: T[K]
}
使用示例
// Partial 生成一个可选的类型
type IOptionalUser = Partial<IUser>
// 再通过Required转化为必选类型
type IRequiredUser = Required<IOptionalUser>
const user: IRequiredUser = {
name: 'Jack',
age: 20,
gender: 'male'
}
其他内置工具
- ThisParameterType<T>
- OmitThisParameterType<T>
- ThisType<T>
额外的非内置类型定义
DeepReadonly<T>
DeepReadonly用来深度遍历 T,并将其所有属性变成只读类型
type DeepReadonly<T> = { readonly [P in keyof T]: DeepReadonly<T[P]> }
ValueOf<T>
ValueOf与keyof相对应。取出指定类型的所有 value
type ValueOf<T> = T[keyof T]
Mutable<T>
用来将所有属性的readonly移除:
type Mutable<T> = {
-readonly [K in keyof T]: T[K]
}