ts的类型工具
看了一遍阮一峰的ts文档,地址:https://wangdoc.com/typescript/utility#capitalizestringtype。ts提供了一些类型工具,在此记录一下,做个总结,加深印象。
字符串的类型工具4种:
Uppercase<S> 字母大写
Lowercase<S> 字母小写
Capitalize<S> 首字母大写
Uncapitalize<S> 首字母小写
其他类型有18种,但其中的3种 OmitThisParameter<Type>
ThisParameterType<Type>
ThisType<Type>
主要是用于this的处理,应用场景少见,所以就不加强记忆了,剩下的15种,我根据处理的类型,即工具入参类型进行分类:
1. 处理Promise,即工具入参为Promise,有1种
1)Awaited<Promise>
2.处理构造函数,有2种
1)ConstructorParameters<Class>
2)InstanceType<Class>
3. 处理对象类型,有6种
1)Omit<Object,K>
2)Pick<Object,K>
3)Readonly<Object>
4)ReadonlyArray<T>
5)Partial<Object>
6)Required<Object>
4. 处理方法,有2种
1)Parameters<Function>
2)ReturnType<Function>
5. 处理联合类型,有4种
1)Exclude<T,U>
2)Extract<T,U>
3)NonNullable<T>
4)Record<K,T>
1. Awaited<P> 返回promise的数据类型
Awaited<P>用来取Promise的返回值,比如描述.then()和await方法返回值。
type DataType = { code: number, data: string, msg: string } export function getDataById(): Promise<DataType> { return new Promise((resolve) => { resolve({ code: 0, data: "我是返回的数据", msg: "success" }) }) } /* 两种A的定义都可以,相当于 type A = DataType */ // type A = Awaited<Promise<DataType>> type A = Awaited<ReturnType<typeof getDataById>> const data: A = { code: 0, data: "", msg: "" }
2. ConstructorParameters<Class> 提取构造方法的参数类型,并通过元组类型返回
ConstructorParameters<C>入参是一个构造方法,可以new的,它用于将new时传入的参数类型提取出来,并用一个数组合并返回。
class Demo { constructor(x: number, y: string) { } } /* 相当于 A = [x:number,y:string] */ type A = ConstructorParameters<typeof Demo> const data1: A = [1, "字符串"] /* 相当于 A = [x:number,y?:string] */ type B = ConstructorParameters<new (x: number, y?: string) => object> const data2: B = [1] const data3: B = [1,"我是可填的字符串"]
3. InstanceType<Class> 提取构造函数的返回值的类型,也就是返回实例类型
InstanceType<Class>入参是一个构造函数,返回的是这个实例
class Demo { constructor(x: number, y: string) { } } type Z = InstanceType<typeof Demo> // 以下两种写法意义一样 const demo1: Z = new Demo(1, "1") const demo2: Demo = new Demo(2, "bbb")
4. Pick<Object,T> 从对象类型中,挑出T中指定的键名,返回一个新的对象类型
从对象类型Object中,挑选出联合类型T中的键名,将挑选出来的组成一个新的对象类型进行返回。注意:T必须是对象类型中已经存在的键名,不然会报错的。
type O = { name: string, address: string, otherInfo: { hobby: string, desc: string } } /* 相当于 P1 = {name:string,address:string} */ type P1 = Pick<O, 'name' | 'address'> const p: P1 = { name: "张三", address: "中国" } /* 报错了,noExist这个键名不存在O中 */ type P2 = Pick<O, 'name' | 'noExist'>
Pick的实现如下:
type Pick<O,T extends keyof O> = { [P in T]:O[p] }
从实现中能看到,T必须是O存在的键名,不然读取O[P]就要报错了,那我们调整一下,传的T可以是O不存在的键名,最后返回结果与Pick一样。
/* P为T与O键名的交叉集,这样就保证键名P一定存在于O */ type PickAdjust<O, T extends keyof any> = { [P in Extract<T, keyof O>]: O[P] }
再调整一下,改为可以传不存在的键名,不存在的键名就给定any类型。
/*
允许T任何类型,然后再通过extends ? 三木运算符给值
如果再严谨一点,改为 T extends keyof number|string|symbol
*/
type PickAdjust<O, T extends keyof any> = { [P in T]: P extends keyof O ? O[P] : any }
5. Omit<Object,T> 从对象类型中,去掉T中指定的键名,返回一个新的对象类型
Omit<Object,T>,从对象类型中,剔除T有提过的键名,返回一个新的对象,这跟Pick相反,一个是留,一个是去。
type O = { name: string, address: string, otherInfo: { hobby: string, desc: string } } /* M相当于O去掉了name和noexist属性 去掉的键名中传O中不存在的键名也是没关系的 */ type M = Omit<O, 'name' | 'noExist'> const m: M = { address: "中国", otherInfo: { hobby: '保护世界', desc: '世界和平' } }
Omit<Object,T> 实现如下:
type Omit<O, T> = Pick<O, Exclude<keyof O, T>>
6. Partial<Object> 将对象的所有属性都变为可选,返回一个新的对象类型
Partial<Object>将对象所有属性都变为可选,K?:T
type O = { name: string, address: string, otherInfo: { hobby: string, desc: string } } /* O中所有的属性都变为可选 */ type X = Partial<O> const x: X = { name: "张三" } !!! 注意,属性的类型如果为对象类型,那还是按照它自身的情况规定可选或必选,这玩意不能传递哈
就比如上面的otherInfo是可选的,但如果你选了它,那它的【hobby】【desc】是必选的,这不能传递到下面。
Partial<Object>实现如下:
type Partial<O> = { [P in keyof O]?: O[P] }
7. Required<Object>将对象的所有属性都变为必选,返回一个新的对象类型
Required<Object>将对象所有属性都变为必选,与Partial<Object>相反,K-?:T,将这?减掉
type O = { name: string, age?: number, otherInfo: { hobby?: string, desc: string } } type R = Required<O> /* 上面O中的age可选,变为了必选 但otherInfo中的hobby还是可选,不会被影响,因为这个不会传递 */ const r: R = { name: "李四", age: 18, otherInfo: { desc: "世界和平" } }
Required<Object>实现如下:
type Required<O> = { [P in keyof O]-?: O[P] }
8. Readonly<Object> 将对象的所有属性都变为只读,返回一个新的对象类型
Readonly<Object>将对象所有属性都变为只读,readonly K:T ,如果是去掉只读,可以写 readonly K:T
type O = { name: string, age?: number, otherInfo: { hobby?: string, desc: string } } type R = Readonly<O> const r: R = { name: "李四", age: 18, otherInfo: { desc: "旧的描述" } } /* 报错 name属性只读,不可赋值 */ r.name = "123" /* 正确 因为只读标志不会传递 */ r.otherInfo.desc = "新的描述"
Readonly<Object>实现如下:
type Readonly<O> = { readonly [P in keyof O]: O[P] }
9. ReadonlyArray<T>用来生成一个只读数组
ReadonlyArray<T>数组只读,不可再修改数组,它的push,splice,pop等都不存在不可用
const values: ReadonlyArray<string> = ['a', 'b', 'c']; values[0] = 'x'; // 报错 values.push('x'); // 报错 values.pop(); // 报错 values.splice(1, 1); // 报错
ReadonlyArray<T>实现如下:
interface ReadonlyArray<T>{
readonly length:number
readonly [n:number]:T
}
10. Parameters<Function>提取方法的入参类型,返回一个元组类型
Parameters<Function>接收一个函数类型,将入参提取出来,并组合为元组类型进行返回。如果该函数没有入参,那就返回一个空数组。
function JoinArg(x: number, y: string): string { return x + y } /* A = [number,string] */ type A = Parameters<typeof JoinArg> const a: A = [1, ""] /* B = [] */ type B = Parameters<() => {}> const b: B = []
Parameters<Function>实现如下:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
11. ReturnType<Function>返回方法的返回值的类型
ReturnType<Function>接受一个函数类型,返回函数返回值的类型。
type R1 = ReturnType<() => void> // void type R2 = ReturnType<() => {}> // {} type R3 = ReturnType<() => { x: number, y: string }> // {x: number, y: string } type R4 = ReturnType<() => Array<string>> // Array<String>
ReturnType<Function>实现如下:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : never
12. Exclude<U,E>从U中剔除E,组合新的类型返回
Exclude<U,E>用来从联合类型U中,剔除某些类型E,组合成一个新的类型返回。可以理解为 U-E的值,如果E中有U不包含的,直接忽略。
type A = number | string | Array<string> type B = number | boolean type T1 = Exclude<A, B> // number | Array<string> type T2 = Exclude<200 | 400, 200 | 201>; // 400 type T3 = Exclude<number, boolean>; // number type T4 = Exclude<string | string[], any[]>; // string type T5 = Exclude<(() => void) | null, Function>; // null
Exclude<U,T>实现如下:
type Exclude<U,T> = U extends T ? never:U
Exclude<number|string,number|boolean>结果是string,number|string
是一个联合类型,进行条件运算时,相当于A
和B
分别进行运算符,返回结果组成一个联合类型。
上面的相当于number extends number|boolean,结果true,得到never;string extends number|boolean,结果false,得到string,集合的结果就是never|string,由于never
类型是任何其他类型的子类型,它跟其他类型组成联合类型时,可以直接将never
类型从联合类型中消掉,所以结果就是string。
13. Extract<U,E>从U中提取出与E的交集,组合新的类型返回
Extract<U,E>从联合类型U中取出E提到的类型,组合成一个新的类型返回。如果E提到的类型在U中不存在,直接忽略。它跟Exclude相反,获取的是U与E的交叉类型
type T1 = Extract<'a'|'b'|'c', 'a'>; // 'a' type T2 = Extract<'a'|'b'|'c', 'a'|'b'>; // 'a'|'b' type T3 = Extract<'a'|'b'|'c', 'a'|'d'>; // 'a' type T4 = Extract<string | string[], any[]>; // string[] type T5 = Extract<(() => void) | null, Function>; // () => void type T6 = Extract<200 | 400, 200 | 201>; // 200
Extract<U,E>实现如下:
type Extract<U, T> = U extends T ? U : never
14. NonNullable<U>从U中剔除null,undefined类型,组合新的类型返回
NonNullable<U>返回非空类型,从联合类型中剔除null,undefined类型。
// string|number type T1 = NonNullable<string|number|undefined>; // string[] type T2 = NonNullable<string[]|null|undefined>; type T3 = NonNullable<boolean>; // boolean type T4 = NonNullable<number|null>; // number type T5 = NonNullable<string|undefined>; // string type T6 = NonNullable<null|undefined>; // never
NonNullable<T>实现如下:
type NonNullable<T> = T & {}
由于 TypeScript 的非空值都属于Object
的子类型,所以会返回自身;而null
和undefined
不属于Object
,会返回never
类型。
15. Record<K,T>K作为键名,T作为键值,组合为一个新的对象类型返回
Record<K,T>将联合类型K作为对象类型的键名,T作为键值,组成一个新的对象类型进行返回。
type T = Record<'a', number>;// {a:number} type T = Record<'a'|'b', number>;// { a: number, b: number } type T = Record<'a', number|string>;// { a: number|string }
Record<K,T>实现如下:
type Record<K extends string|number|symbol,T>={ [P in K]:T }
16.1. Uppercase<StringType> 字母大写
16.2. Lowercase<StringType> 字母小写
16.3. Capitalize<StringType> 首字母大写
16.4. Uncapitalize<StringType> 首字母小写
type A = 'hello'; type B = Uppercase<A>;// "HELLO" type A = 'HELLO'; type B = Lowercase<A>;// "hello" type A = 'hello'; type B = Capitalize<A>;// "Hello" type A = 'HELLO'; type B = Uncapitalize<A>;// "hELLO"