获取函数的返回类型

问题描述 投票:0回答:10

我有以下功能:

function test(): number {
    return 42;
}

我可以使用

typeof
获取函数的类型:

type t = typeof test;

在这里,

t
将是
() => number

有没有办法获取函数的返回类型?我希望

t
成为
number
而不是
() => number

typescript typescript1.8
10个回答
403
投票

编辑

从 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[]

有关详细信息,请参阅向 Microsoft/TypeScript 发出的拉取请求

TypeScript 太棒了!


老派黑客

不幸的是,瑞安的答案不再有效。但我用一个 hack 修改了它,我对此感到非常高兴。看哪:

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

它的工作原理是将

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


146
投票

TypeScript 2.8 中最简单的方法:

const foo = (): FooReturnType => {
}

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

13
投票

使用内置

ReturnType

type SomeType = ReturnType<typeof SomeFunc>

ReturnType
扩展为:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

5
投票

下面的代码无需执行该函数即可工作。它来自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;

3
投票

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

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

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

3
投票

编辑: TS 2.8 不再需要此功能!

ReturnType<F>
给出返回类型。查看已接受的答案。


我之前使用的一些答案的变体,它适用于

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
函数,但它没有调用原始函数。您可以使用
getReturnType
阻止
(false as true) && getReturnType(foo)
调用,但在我看来,这只会让事情变得更加混乱。

我只是使用这个方法和一些正则表达式查找/替换来迁移一个旧的 Angular 1.x 项目,该项目有大约 1500 个像这样编写的工厂函数,最初是用 JS 编写的,并将

Foo
等类型添加到所有用途......太棒了人们会发现损坏的代码。 :)


2
投票

如果相关函数是用户定义类的方法,您可以将 方法装饰器Reflect Metadata 结合使用来确定 runtime 的返回类型(构造函数)(并使用它,按照您的方式操作看看合适)。

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

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
  • 得到未定义的结果
  • 只能引用编译后也存在的实际类型;也就是说,没有接口或泛型

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

--emitDecoratorMetadata --experimentalDecorators

0
投票

我想出了以下方法,看起来效果很好:

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

0
投票

以防万一您有一个类并且您想获取方法的返回类型:

class MeaningOfLife {
  public get() {
    return 42 as const;
  }
}

您可以访问类的原型,以便将方法作为函数获取:

export type Answer = ReturnType<typeof MeaningOfLife.prototype.get>; // equals the literal 42

这非常好,因为有时 TypeScript 能够分析代码来推断复杂类型


0
投票
const foo = ()=>{
   return {name: "test", age: 5}
}
type T1 = ReturnType<typeof foo> // {name: string, age: number}
type T2 = ReturnType<typeof foo>['name'] // string
type T3 = T1['age'] // number
© www.soinside.com 2019 - 2024. All rights reserved.