08 泛型函数实战工具函数

114 阅读2分钟

基础

掌握简单的泛型函数的书写了吗?

是的

好的开始进阶吧

进阶

ReturnType 泛型函数的实现?

关键点1 利用条件判断类型, extends 在这里是用来判断是否相等或是其subtype

type NumOrStr<T> = T extends number ? number : string // 条件判断 

关键点2 限制传入的参数是函数类型

type IsFnType<T> = T extends (...args: any) => any ? true : false // 条件判断 

关键点3 利用条件判断类型中的 infer 来提取出函数类型中的可变返回参数类型

type ReturnGeneric<T> = T extends (...args: any) => infer R ? R : any // 条件判断 

Parameters 泛型函数?

利用条件判断类型中的 infer 来提取出函数类型中的可变传入参数类型

 // Parameters<Type> => Tuple Type
 type ParamsGeneric<T extends (...args: any) => any> = T extends (
    ...args: infer ArgsType
  ) => any
    ? ArgsType
    : any; // 条件判断

  type P0 = ParamsGeneric<() => string>;
  type P1 = ParamsGeneric<(a: string | number) => string>;

ConstructorParameters怎么实现?

通过类型系统中泛型函数特殊的循环排除语法去做到

  // ConstructorParameters<Type>
  type T0 = ConstructorParameters<ErrorConstructor>;
  // 限制传入参数符合 abstract new (...args: any) => any 即能通过 new Fn() 调用
  // 通过条件判断类型关键字 infer 提取 args
  type ConstructorGeneric<T extends abstract new (...args: any) => any> =
    T extends abstract new (...args: infer P) => any ? P : never;
  
  interface Book { 
    new(author: string, title: string): void;
  }

  type T1 = ConstructorGeneric<Book>
  type T2 = ConstructorGeneric<DateConstructor>

InstanceType 泛型函数实现?

提取返回的实例

关键点还是 限制参数,通过条件判断类型中的 infer 提取返回参数

type InstanceGeneric<T extends abstract new (...args: any) => any> =
   T extends abstract new (...args: any) => infer InstanceType ? InstanceType : never;

ThisParameterType => ThisType | unknown?

  type toHex = (this: number) => string;

  type T0 = ThisParameterType<toHex>;

  type ThisGeneric<T> = T extends (this: infer ThisType, ...args: never) => any
    ? ThisType
    : unknown;

  type T1 = ThisParameterType<toHex>;

OmitThisParameter 去除this: Type?

第一个判断 unknown extends ThisParameterType 没有 this parameters 直接返回 T
第二个判断 T 有 this parameters 即符合 (this: any,...args: any) => any,直接 infer 提取 args , 返回参数类型组成去除this parameters的类型 (...args: A) => R


  type toHex = (this: number) => string;

  type T0 = OmitThisParameter<toHex>;


  type OmitThisGeneric<T> = unknown extends ThisParameterType<T>
    ? T
    : T extends (...args: infer A) => infer R
      ? (...args: A) => R
      : T;

  type T1 = OmitThisGeneric<toHex>;

  type T2 = OmitThisGeneric<string>;