【问题标题】:Is there ArgumentsType<T> like ReturnType<T> in Typescript?Typescript 中是否有类似 ReturnType<T> 的 ArgumentsType<T>?
【发布时间】:2022-03-02 11:39:06
【问题描述】:

ReturnType&lt;T&gt; 提取函数的返回类型。

有没有办法定义ArgumentsType&lt;T&gt;,以tuple 格式提取函数的参数类型?

例如,

ArgumentsType&lt;(a: number, b: string) =&gt; boolean&gt; 将是 [number, string]

【问题讨论】:

    标签: typescript


    【解决方案1】:

    编辑

    自从写出原始答案以来,typescript 现在有一个内置类型(在lib.d.ts 中定义)来获取名为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)?]
    

    编辑 Typescript 3.0 已发布,以下代码按预期工作。

    虽然在当前版本的 typescript (2.9) 中,如果不拼写所有参数,这是不可能的。这将在未来几天发布的下一版 typescript (3.0) 中成为可能:

    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)?]
    

    如果您安装了npm install typescript@next,您已经可以使用它,它应该在本月的某个时候可用。

    注意

    我们还可以使用这个新功能将元组传播到参数中:

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

    您可以阅读有关此功能的更多信息here

    【讨论】:

    • 期待!谢谢!
    • @Joon 我也是,我将不得不重写很多答案,这个功能让一切变得更简单:)
    • @TitianCernicova-Dragomir 只是想知道。如果我需要在类中获取函数的参数类型怎么办。换句话说,我如何在课堂上使用ParametersThis 应该更清楚
    • @NahushFarkande 你需要使用Parameters&lt;ClassName['methodName']&gt; 不要忘记为有用的答案投票;)
    • @NahushFarkande 以 b(param: Parameters&lt;myClass['a']&gt; [0])b(param: Parameters&lt;this['a']&gt; [0]) 为例(但我通常会避免多态。
    【解决方案2】:

    从 TypeScript 3.1 开始,Parameters 类型现在是标准库的一部分。

    type Result = Parameters<(a: number, b: string) => boolean>; // [number, string]
    

    【讨论】:

    • 什么版本?似乎不在 3.0.1 中
    • pull request 没有提到任何里程碑,但它肯定存在于 TypeScript 3.1 中。
    【解决方案3】:

    目前无法为任何可能的函数同时提取类型数量的参数。但是你可以试试这样的:

    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;
    

    通过以下方式检查:

    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
    

    请注意,这不使用任何可选参数 - 它们只是从输出中省略。我暂时无法找到捕捉它们的方法。

    【讨论】:

    • 这在 3.0 之前很有用。谢谢!
    • @Joon 即使在 3 之后,它也有助于解决 TypeScript 中使用 function overloads 的未解决问题,而其他人提出了 similar workaround
    【解决方案4】:

    对于我的问题,我使用了以下样式:

    const myFunction = <T>(items: T[], config: FuseConfigType) => {
      const fuse = new Fuse(items, config);
    
      return (pattern: string): T[] =>
        pattern === '' ? items : fuse.search(pattern).map(({ item }) => item);
    };
    
    export default fuseSearch;
    
    

    我得到 T 类型,即 items 中每个项目的类型,然后当我想返回函数时,我使用 T 传递它,就像我得到它一样。

    【讨论】:

      【解决方案5】:

      我创建了一组常见的辅助类型,如下所示:https://github.com/joonhocho/tsdef

      您可以在这里找到许多打字稿的辅助模式。 你也可以通过 npm 或 yarn 安装。 npm i -D tsdef

      【讨论】:

        【解决方案6】:

        我确信Parameters&lt;T&gt; 有很多用途,但我想要一种方法来为私有成员上的相同方法提供代理方法,这似乎非常合适。

        例如。我想要以下内容,这样如果authService.login 签名发生更改,我就不必修改我的代理——只要调用它。

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

        使用Parameters&lt;T&gt;,您可以执行以下操作

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

        当然,好处是如果你有复杂的参数,它会很好地照顾自己 - (可能不会只为两个字符串推荐这个!)

        我尝试了几次才发现我在两次出现 params 时都需要 ...

        【讨论】:

          【解决方案7】:

          扩展@Titian Cernicova-Dragomir's answer,如果您使用命名函数表达式,因此无法定义类型,您可以使用typeof 访问参数,如下所示:

          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];
          
            // ...
          }
          

          【讨论】:

            【解决方案8】:

            如果函数参数在 class 上,那么您可以使用以下方法来提取它们:

            class Foo {
              bar(a: string, b: number) {
                // Want these ^
              }
            }
            
            type BarFn = Foo['bar']; 
            //     ^  (a: string, b: number) => void
            type BarFnArguments = Parameters<BarFn>;
            //     ^  [string, number]
            type FirstArg  = BarFnArguments[0]
            //     ^  string
            type SecondArg  = BarFnArguments[1]
            //     ^  number
            

            对于单元测试模拟很有用,有时可以用玩笑对其进行无类型化。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-05-30
              • 1970-01-01
              • 2020-01-28
              • 2022-11-03
              • 2021-07-19
              • 2010-09-28
              • 1970-01-01
              相关资源
              最近更新 更多