TS能够通过一些逻辑语法去提取我们想要的类型和结果、在此之前我们需要先了解 infer(局部变量)和 extends ? : 类似JS的三元算符后面的案例中我们讲大量使用它!

Promsie

  1. type p = Promise<'gf'>
  2. type getValueType = p extends Promise<infer Value> ? Value : never;
  3. /*
  4. 通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,
  5. 否则就返回 never 代表没匹配到
  6. */

Array

  1. type arr = [1,2,3]
  2. // 提取arr第一个元素的类型
  3. type GetFirst<Arr extends number[]> = Arr extends [infer First, ...number[]] ? First : never;
  4. type res = GetFirst<arr> // [1]
  5. // 提取最后一个
  6. type GetLast<Arr extends number[]> = Arr extends [ ...number[], infer Last] ? Last : never;
  7. type res1 = GetLast<arr> // [3]
  8. // 提取剩下的
  9. type PopArr <Arr extends number[]> = Arr extends [ ...infer Rest, number] ? Rest : never;
  10. type res2 = PopArr<arr> // [1,2]

String

  1. type str = 'guang2222fa';
  2. // 匹配字符串是不是以xxx开头
  3. type StartWith<Str extends string, Prefix extends string> =
  4. Str extends `${Prefix}${string}` ? true : false;
  5. type res = StartWith<str, 'g'> // true
  6. type res1 = StartWith<str, 'h'> // false
  7. /*
  8. 解释:
  9. 接收两个参数 Str强制匹配为string类型、Prefix前缀,${string}是指任意的string、
  10. */
  11. // 字符串替换
  12. type ReplaceStr<Str extends string, Substr extends string, Replacement extends string> =
  13. Str extends `${infer Prefix}${Substr}${infer Suffix}`
  14. ? `${Prefix}${Replacement}${Suffix}` : Str;
  15. type res2 = ReplaceStr<str, '2222', '&&&'> //"guang&&&fa"
  16. // Trim去除空格(利用递归一个一个去找)
  17. type TrimLeft<Str extends string> =
  18. Str extends `${' ' | '\n' | '\t'}${infer Rest}`
  19. ? TrimLeft<Rest>
  20. : Str;
  21. type res3 = TrimLeft<" gf"> //gf
  22. // right
  23. type TrimStrRight<Str extends string> =
  24. Str extends `${infer Rest}${' ' | '\n' | '\t'}`
  25. ? TrimStrRight<Rest> : Str;
  26. type res4 = TrimStrRight<'gf '>
  27. // 组合Trim
  28. type TrimStr<Str extends string> =TrimStrRight<TrimStrLeft<Str>>;
  29. type res5 = TrimStr<' gf '> // gf

Function

  1. // 提取参数
  2. type GetParams<Func extends Function> =
  3. Func extends (...args:infer Params) => unknown
  4. ? Params : never;
  5. type ParamsResult = GetParams<(name:string, age:number) => string> // [name: string, age: number]
  6. // 返回类型
  7. type GetReturnType<Func extends Function> =
  8. Func extends (...args: unknown[]) => infer ReturnType
  9. ? ReturnType : never;
  10. type ReturnTypeResult = GetReturnType<() => 'gf'> // gf

Class

  1. class Gf {
  2. name: string;
  3. constructor() {
  4. this.name = "gf";
  5. }
  6. hello() {
  7. return 'hello, I\'m ' + this.name;
  8. }
  9. }
  10. const gf = new Gf();
  11. gf.hello();
  12. // 方法也可以使用call 或者bind 、apply
  13. gf.hello.call({name:'111'}) // 但这里却没有被检查出来 this 指向的错误。
  14. // 修改
  15. class Gf {
  16. name: string;
  17. constructor() {
  18. this.name = "gf";
  19. }
  20. // 需注意,这里的 this 经过 ts 编译后会消失
  21. hello(this: Gf) {
  22. return 'hello, I\'m ' + this.name;
  23. }
  24. }
  25. // 这样就能检测出有问题的this、这里的this还能够提取出来
  26. type GetThisParameterType<T> =
  27. T extends (this: infer ThisType, ...args:any[]) => any
  28. ? ThisType
  29. : unknown;

总结

类型的提取是TS类型计算的一个基础、学习不同类型的提取套路、在结合后面的学习、我们就能更加灵活的编写TS的逻辑类型计算!