Is there ArgumentsType like ReturnType in Typescript?

前端 未结 6 673
一个人的身影
一个人的身影 2020-11-30 12:34

ReturnType extracts return type of a function.

Is there a way to define ArgumentsType that extracts parameter types of a

相关标签:
6条回答
  • 2020-11-30 12:47

    I created a collection of common helper types like this: https://github.com/joonhocho/tsdef

    Here's you can find many helper patterns for typescript. you can install via npm or yarn as well. npm i -D tsdef

    0 讨论(0)
  • 2020-11-30 12:58

    As of TypeScript 3.1, Parameters type is now a part of the standard library.

    type Result = Parameters<(a: number, b: string) => boolean>; // [number, string]
    
    0 讨论(0)
  • 2020-11-30 13:00

    There is no way for now to extract both the types and amount of arguments for any function possible. But you can try something like this:

    type ArgumentTypes<T> = T extends () => any ? never[] :
                            T extends (a1: infer T1) => any ? [T1] :
                            T extends (a1: infer T1, a2: infer T2) => any ? [T1, T2] :
                            // continue here for any reasonable number of args
                            never;
    

    Check it with the following:

    const args0: ArgumentTypes<() => boolean> = []; // correct
    const args1: ArgumentTypes<(a: number) => boolean> = [1]; // correct
    const args2: ArgumentTypes<(a: number, b: string) => boolean> = [1, 'str']; // correct
    
    const oops0null: ArgumentTypes<() => boolean> = null; // error, arguments are array (but empty one)
    const oops01: ArgumentTypes<() => boolean> = [1]; // error, arguments must be empty
    
    const oops10: ArgumentTypes<(a: number) => boolean> = []; // error, we need one argument
    const oops12: ArgumentTypes<(a: number) => boolean> = [1, 2]; // error, we need only one argument
    const oops1wrong: ArgumentTypes<(a: number) => boolean> = ['str']; // error, argument must be number
    
    const oops21: ArgumentTypes<(a: number, b: string) => boolean> = [1]; // error, we need two arguments
    const oops23: ArgumentTypes<(a: number, b: string) => boolean> = [1, 'str', undefined]; // error, we need only two arguments
    const oops2wrong: ArgumentTypes<(a: number, b: string) => boolean> = ['str', 1]; // error, arguments are reversed
    

    Note that this don't have any use of optional arguments - they are just omitted from the output. I wasn't able to find a way to catch them for now.

    0 讨论(0)
  • 2020-11-30 13:02

    I'm sure there are many uses for Parameters<T> but I wanted a way to provide proxy method to the same method on a private member and it seemed a perfect fit.

    eg. I want to have the following, such that if the authService.login signature changes I don't have to modify my proxy - just whatever is calling it.

    login(username: string, password: string) { this.authService.login(username, password); }
    

    With Parameters<T> you can do the following

    login = (...params: Parameters<AuthService['login']>) => this.authService.login(...params);
    

    Of course the benefit is that if you have complex parameters it'll just take care of itself nicely - (probably wouldn't recommend this for just two strings!)

    It took me a couple attempts to figure out that I needed ... on both occurrences of params.

    0 讨论(0)
  • 2020-11-30 13:04

    Edit

    Since writing the original answer, typescript now has a built-in type (defined in lib.d.ts) to get the type of the parameters called Parameters

    type argsEmpty = Parameters<() => void> // []
    type args = Parameters<(x: number, y: string, z: boolean) => void> // [number, string, boolean]
    type argsOpt = Parameters<(x: number, y?: string, z?: boolean) => void> // [number, (string | undefined)?, (boolean | undefined)?]
    

    Edit Typescript 3.0 has been relesed the code below works as expected.

    While this is not possible in the current version of typescript (2.9) without spelling out all parameters. It will become possible in the next version of typescript (3.0) which will be released in the next few days:

    type ArgumentsType<T> = T extends  (...args: infer U) => any ? U: never;
    
    type argsEmpty = ArgumentsType<() => void> // []
    type args = ArgumentsType<(x: number, y: string, z: boolean) => void> // [number, string, boolean]
    type argsOpt = ArgumentsType<(x: number, y?: string, z?: boolean) => void> // [number, (string | undefined)?, (boolean | undefined)?]
    

    If you install npm install typescript@next you can already play with this, it should be available sometime this month.

    Note

    We can also spread a tuple into arguments with this new feature:

    type Spread<T extends any[]> = (...args: T)=> void;
    type Func = Spread<args> //(x: number, y: string, z: boolean) => void
    

    You can read more about this feature here

    0 讨论(0)
  • 2020-11-30 13:13

    Expanding on @Titian Cernicova-Dragomir's answer, if you are using named function expressions, thus not being able to define a type, you can access the parameters with typeof like so:

    function updateTable<T extends IHasOBJECT_ID>(
      diff: Diff,
      cache: { [id: string]: Table<T, Array<keyof T>> & IHasOBJECT_ID & IHasCONFLICTS & IHasOPTIONS },
    ) {
      // Use typeof to get the parameter type for cache
      const cacheItem: Parameters<typeof updateTable>[1] = cache[diff.id];
    
      // ...
    }
    
    0 讨论(0)
提交回复
热议问题