Typescript 类型的模式匹配是通过 extends 对类型参数做匹配,结果保存到通过 infer 声明的局部类型变量里,如果匹配就能从该局部变量里拿到提取出的类型。
数组类型 First 1 2 3 type First <T extends unknown []> = T extends [infer R, ...unknown []] ? R : never ;type res = First <["1" , 2 , 999 ]>;
类型参数 T 通过 extends 约束为只能是数组类型,数组元素是 unkown 也就是可以是任何值。
对 T 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 R 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。
Last 1 2 3 type Last <T extends unknown []> = T extends [...unknown [], infer R] ? R : never ;type res1 = Last <["1" , 2 , 999 ]>;
PopArr 1 2 3 type PopArr <T extends unknown []> = T extends [...infer U, infer R] ? U : never ;type res2 = PopArr <["1" , 2 , 999 ]>;
ShiftArr 1 2 3 4 5 type ShiftArr <T extends unknown []> = T extends [infer U, ...infer R] ? R : never ; type res3 = ShiftArr <["1" , 2 , 999 ]>;
字符串类型 匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。
判断字符串是否以某个前缀开头 StartsWith 1 2 3 4 5 6 7 8 9 type StartsWith < Str extends string , prefix extends string > = Str extends `${prefix} ${string } ` ? true : false ; type res4 = StartsWith <"aba bbb ccc" , "aba" >;type res5 = StartsWith <"aba bbb ccc" , "abc" >;
字符串替换 Replace 1 2 3 4 5 6 7 8 9 10 11 type ReplaceStr < Str extends string , From extends string , To extends string > = Str extends `${infer prefix} ${From} ${infer SuffFix} ` ? `${prefix} ${To} ${SuffFix} ` : never ; type res6 = ReplaceStr <"li is a good person" , "good" , "bad" >;type res7 = ReplaceStr <"li is a good person ?" , "?" , "!" >;
Trim 实现去掉空白字符的 Trim:
不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type TrimRight <Str extends string > = Str extends `${infer Rest} ${ | " " | "\n" | "\r" } ` ? TrimRight <Rest > : Str ; type TrimLeft <Str extends string > = Str extends `${ | " " | "\n" | "\r" } ${infer Rest} ` ? TrimLeft <Rest > : Str ; type res8 = TrimRight <"aaa " >;type res9 = TrimLeft <" aaa " >;type Trim <Str extends string > = TrimRight <TrimLeft <Str >>;type res10 = Trim <" aaa " >;
函数类型 参数类型 1 2 3 4 5 6 7 type GetParameters <Fn extends Function > = Fn extends ( ...args : infer Args ) => unknown ? Args : never ; type res = GetParameters <(name: number ) => void >;
返回值类型 1 2 3 4 5 6 7 8 9 type GetReturnType <Fn extends Function > = Fn extends ( ...args : any [] ) => infer R ? R : never ; type res1 = GetReturnType <(name: number ) => string >;
this 类型 方法里可以调用 this,比如这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Dong { name : string; constructor ( ) { this .name = "dong" ; } hello ( ) { return 'hello, I\'m ' + this .name ; } } const dong = new Dong ();dong.hello ();
用对象.方法名
的方式调用的时候,this 就指向那个对象。
但是方法也可以用 call 或者 apply 调用:
1 dong.hello ().call ({xxx :1 });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Dong { name : string ; constructor ( ) { this .name = "dong" ; } hello (this : Dong ) { return "hello, I'm " + this .name ; } } const dong = new Dong ();dong.hello (); dong.hello .call ({ xxx : 1 }); type GetThisParameterType <T> = T extends (this : infer U) => any ? U : never ;type res7 = GetThisParameterType <typeof dong.hello >;
构造器类型 构造器类型可以用 interface 声明,使用 new(): xx 的语法。
1 2 3 4 5 6 7 interface Person { name : string ; } interface PersonConstructor { new (name : string ): Person ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 interface Person { name : string ; } interface PersonConstructor { new (name : string ): Person ; } type GetInstanceType <ConstructorType extends new (...args : any ) => any > = ConstructorType extends new (...args : any ) => infer InstanceType ? InstanceType : any ; type res8 = GetInstanceType <PersonConstructor >;type GetConstructorParameters < ConstructorType extends new (...args : any ) => any > = ConstructorType extends new (...args : infer ParametersType ) => any ? ParametersType : never ; type res9 = GetConstructorParameters <PersonConstructor >;
索引类型 索引类型也同样可以用模式匹配提取某个索引的值的类型
1 2 3 4 5 type GetRefProps <Props > = "ref" extends keyof Props ? Props extends { ref?: infer Value | undefined } ? Value : never : never ;
类型参数 Props 为待处理的类型。
通过 keyof Props 取出 Props 的所有索引构成的联合类型,判断下 ref 是否在其中,也就是 ‘ref’ extends keyof Props。
在 ts3.0 里面如果没有对应的索引,Obj[Key] 返回的是 {} 而不是 never,所以这样做下兼容处理。
如果有 ref 这个索引的话,就通过 infer 提取 Value 的类型返回,否则返回 never。