我有以下功能:

function test(): number {
    return 42;
}

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

type t = typeof test;

这里t是()=> number。

是否有方法获取函数的返回类型?我希望t是number而不是()=> number。


当前回答

编辑:这是不需要与TS 2.8更多!>给出返回类型。见已接受答案。


我使用的一些以前答案的变体,它在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为true) && getReturnType(foo)来防止getReturnType调用,但在我看来,这只会让它更混乱。

我只是使用这个方法和一些regexp find/replace来迁移旧的Angular 1。x项目有大约1500个工厂函数是这样写的,最初是在JS中,并添加了Foo等类型到所有用途…你会发现令人惊讶的坏代码。:)

其他回答

使用内置的ReturnType:

type SomeType = ReturnType<typeof SomeFunc>

ReturnType扩展为:

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

在TypeScript 2.8中最简单的方法是:

const foo = (): FooReturnType => {
}

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

如果所讨论的函数是用户定义类的方法,则可以将方法装饰器与Reflect 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;
    }
}

然而,这种方法有一些明显的局限性:

你需要显式地定义一个方法的返回类型,否则你会得到undefined从Reflect.getMetadata, 你只能引用编译后仍然存在的实际类型;也就是说,没有接口或泛型


此外,你还需要为typescript编译器指定以下命令行参数,因为在写这篇文章时,装饰器和反射元数据都是实验性的特性:

--emitDecoratorMetadata --experimentalDecorators

编辑:这是不需要与TS 2.8更多!>给出返回类型。见已接受答案。


我使用的一些以前答案的变体,它在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为true) && getReturnType(foo)来防止getReturnType调用,但在我看来,这只会让它更混乱。

我只是使用这个方法和一些regexp find/replace来迁移旧的Angular 1。x项目有大约1500个工厂函数是这样写的,最初是在JS中,并添加了Foo等类型到所有用途…你会发现令人惊讶的坏代码。:)

EDIT

从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的pull request。

TypeScript太棒了!


老式的黑客

不幸的是,瑞安的答案已经不管用了。但我用一个黑客修改了它,我对此感到非常高兴。见:

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

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