【问题标题】:Obtaining the return type of a function获取函数的返回类型
【发布时间】:2016-07-01 03:40:32
【问题描述】:

我有以下功能:

function test(): number {
    return 42;
}

我可以通过typeof获取函数的类型:

type t = typeof test;

这里,t 将是 () => number

有没有办法获取函数的返回类型?我希望 t 成为 number 而不是 () => number

【问题讨论】:

  • 不,无论如何都不是 typeof。 typeof 只会返回“function”(我的大小写可能是错误的)。
  • 如果这成为可能,那就太好了。有时,您在将类型推出函数时定义类型,并且没有(好的)方法来捕获这种结构。

标签: typescript typescript1.8


【解决方案1】:

编辑

从 TypeScript 2.8 开始,这可以通过 ReturnType<T> 正式实现。

type T10 = ReturnType<() => string>;  // string
type T11 = ReturnType<(s: string) => void>;  // void
type T12 = ReturnType<(<T>() => T)>;  // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]

详情请见this pull request to Microsoft/TypeScript

TypeScript 太棒了!


老派黑客

不幸的是,Ryan 的回答不再有效。但是我用一个我非常高兴的黑客修改了它。看:

const fnReturnType = (false as true) && fn();

它通过将false 转换为true 的字面值来工作,这样类型系统就会认为返回值是函数的类型,但是当你实际运行代码时,它会在false 上短路.

【讨论】:

  • for flow: const DUMMY = ((null: any): Object) && fn() export type Type = typeof DUMMY
  • @NSjonas 你需要告诉 vscode 使用其他版本。我想他在右下角的状态栏上。
  • 我不得不做ReturnType&lt;typeof fn&gt;(答案暗示ReturnType&lt;fn&gt;就足够了)。
  • 我怎样才能取消看到这个?
  • 是否有类似的方法来获取函数的参数?
【解决方案2】:

TypeScript 2.8 中最简单的方法:

const foo = (): FooReturnType => {
}

type returnType = ReturnType<typeof foo>;
// returnType = FooReturnType

【讨论】:

    【解决方案3】:

    编辑: TS 2.8 不再需要此功能! ReturnType&lt;F&gt; 给出返回类型。查看已接受的答案。


    我正在使用的一些先前答案的变体,它适用于strictNullChecks,并稍微隐藏了推理体操:

    function getReturnType<R>(fn: (...args: any[]) => R): R {
      return {} as R;
    }
    

    用法:

    function foo() {
      return {
        name: "",
        bar(s: string) { // doesn't have to be shorthand, could be `bar: barFn` 
          return 123;
        }
      }
    }
    
    const _fooReturnType = getReturnType(foo);
    export type Foo = typeof _fooReturnType; // type Foo = { name: string; bar(s: string): number; }
    

    确实调用getReturnType函数,但它调用原始函数。您可以使用(false as true) &amp;&amp; getReturnType(foo) 阻止getReturnType 调用,但IMO 只会让它更加混乱。

    我只是使用这个方法和一些正则表达式查找/替换来迁移一个旧的 Angular 1.x 项目,该项目有大约 1500 个这样编写的工厂函数,最初是在 JS 中,并将 Foo 等类型添加到所有用途中。 . 令人惊奇的破代码会发现。 :)

    【讨论】:

    • 谢谢!虽然很遗憾,它需要这么多的措辞,但它至少有效!
    • @ecmanaut 我们不再需要这个了!在 TS 2.8 中,您可以使用 ReturnType&lt;F&gt; 获取函数返回类型。 :)
    • 这里的答案与问题的示例基础大相径庭,因此很难弄清楚如何生成函数 test 的返回类型。这个答案是仅将test 重命名为foo 的更有用的答案之一(并且诚然会产生更复杂的返回类型,用于踢球)。如果您已经知道如何将它们应用于原始示例,那么接受的答案和您的评论可能都很棒。 (现在是深夜,我并没有立即看出完整的 ReturnType 示例的语法是什么样的。)
    【解决方案4】:

    下面的代码在不执行函数的情况下工作。它来自 react-redux-typescript 库 (https://github.com/alexzywiak/react-redux-typescript/blob/master/utils/redux/typeUtils.ts)

    interface Func<T> {
        ([...args]: any, args2?: any): T;
    }
    export function returnType<T>(func: Func<T>) {
        return {} as T;
    }
    
    
    function mapDispatchToProps(dispatch: RootDispatch, props:OwnProps) {
      return {
        onFinished() {
          dispatch(action(props.id));
        }
      }
    }
    
    const dispatchGeneric = returnType(mapDispatchToProps);
    type DispatchProps = typeof dispatchGeneric;
    

    【讨论】:

      【解决方案5】:

      我想出了以下方法,似乎效果很好:

      function returnType<A, B, Z>(fn: (a: A, b: B) => Z): Z
      function returnType<A, Z>(fn: (a: A) => Z): Z
      function returnType<Z>(fn: () => Z): Z
      function returnType(): any {
          throw "Nooooo"
      }
      
      function complicated(value: number): { kind: 'complicated', value: number } {
          return { kind: 'complicated', value: value }
      }
      
      const dummy = (false as true) && returnType(complicated)
      type Z = typeof dummy
      

      【讨论】:

      • 我认为函数 args 不需要是通用的,因为无论如何你都要把它们扔掉。 fn: (...args: any[]) =&gt; Z 就是你所需要的。
      【解决方案6】:

      如果所讨论的函数是用户定义类的方法,您可以结合使用method decoratorsReflect Metadata 来确定运行时 的返回类型(构造函数)(并使用它,做你认为合适的事)。

      例如,您可以将其记录到控制台:

      function logReturnType(
          target: Object | Function,
          key: string,
          descriptor: PropertyDescriptor
      ): PropertyDescriptor | void {
          var returnType = Reflect.getMetadata("design:returntype", target, key);
      
          console.log(returnType);
      }
      

      只需将此方法装饰器捕捉到您选择的方法上,您就可以准确引用从方法调用返回的对象的构造函数。

      class TestClass {
          @logReturnType // logs Number (a string representation)
          public test(): number {
              return 42;
          }
      }
      

      不过,这种方法有一些明显的局限性:

      • 您需要在这样装饰的方法上显式定义返回类型,否则您会从Reflect.getMetadata 得到未定义,
      • 只能引用编译后也存在的实际类型;也就是说,没有接口或泛型

      此外,您需要为 typescript 编译器指定以下命令行参数,因为在撰写本文时,装饰器和反射元数据都是实验性功能:

      --emitDecoratorMetadata --experimentalDecorators
      

      【讨论】:

        【解决方案7】:

        没有办法做到这一点(请参阅https://github.com/Microsoft/TypeScript/issues/6606 了解添加此的工作项跟踪)。

        一种常见的解决方法是编写如下内容:

        var dummy = false && test();
        type t2 = typeof dummy;
        

        【讨论】:

        • 我认为这种变通办法不再有效 - 可能是因为基于控制流的类型分析。
        • @JKillian 你是对的,建议的例子不再有效,虽然你可以很容易地用!1而不是false欺骗TypeScript——typescriptlang.org/play/…
        猜你喜欢
        • 2018-11-06
        • 2015-09-14
        • 2012-01-29
        • 1970-01-01
        • 2018-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多