TypeScript: Is it possible to get the return type of a generic function?

前端 未结 3 367
失恋的感觉
失恋的感觉 2020-12-17 16:27

I have exported a function from some module that looks like:

export function MyFunc() {
    return {
        foo: (in: A) => void
    }
}
         


        
3条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-17 16:53

    Titian's solution above works great if the Generic is only applied inside the function body.

    However, there are cases that the Generic Type is a part of the arguments and/or return type. e.g.

    function MyFunc3(r: number, p: T, x: boolean): T {
        return p;
    }
    

    So, to generalize Titian's solution and support fixating both the arguments and the return type of any generic function, I wrote the following:

    Required Utility Types

    // From https://stackoverflow.com/a/53808212 by jcalz (https://stackoverflow.com/users/2887218)
    export type IfEquals =
        (() => G extends T ? 1 : 2) extends
        (() => G extends U ? 1 : 2) ? Y : N;
    
    // Aidin: Please comment if you could make the following shorter!
    type ReplaceType = IfEquals;
    type ReplaceTypeInArray =
        ARR extends [] ? []
        : ARR extends [infer P0] ? [P0 extends F ? T : P0]
        : ARR extends [infer P0, infer P1] ? [ReplaceType, ReplaceType]
        : ARR extends [infer P0, infer P1, infer P2] ? [ReplaceType, ReplaceType, ReplaceType]
        : ARR extends [infer P0, infer P1, infer P2, infer P3] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType]
        : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType]
        : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType]
        : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5, infer P6] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType]
        : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5, infer P6, infer P7] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType]
        : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5, infer P6, infer P7, infer P8] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType]
        : never;
    

    Sample Functions

    type ALL = string | number | object | boolean;
    
    export function MyFunc1() {
      return {
        foo: (os : T) => {}
      }
    }
    
    function MyFunc2(r: 55, p: T, x: boolean): T {
        return p;
    }
    

    Fixation examples

    // Inspired by https://stackoverflow.com/a/52964723 by Titian (https://stackoverflow.com/users/125734)
    class Helper1  {
        Fixate = (...args: ReplaceTypeInArray, ALL, T>) => MyFunc1(...args);
    }
    type FixatedFunc1 = Helper1['Fixate'];
    
    // -- Usage
    
    type ForNumber1 = FixatedFunc1 //  {foo: (os: number) => void;}
    type ForString1 = FixatedFunc1 //  {foo: (os: string) => void;}
    
    // ~~~~~~~~~~~~~~~~~~~
    
    class Helper2  {
        Fixate = (...args: ReplaceTypeInArray, ALL, T>) => MyFunc2(...args);
    }
    type FixatedFunc2 = Helper2['Fixate'];
    
    // -- Usage
    
    type ForNumber2 = FixatedFunc2 //  (args_0: 55, args_1: number, args_2: boolean) => number
    type ForString2 = FixatedFunc2 //  (args_0: 55, args_1: string, args_2: boolean) => string
    

    Playground Link (Contains all 3 parts)

    Now, one can simply use ReturnType or Parameteres on any of these fixated function types!

提交回复
热议问题