获取函数的返回类型


100

我有以下功能:

function test(): number {
    return 42;
}

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

type t = typeof test;

在这里,t将是() => number

有没有办法获取函数的返回类型?我想tnumber不是() => number


2
不,无论如何都不能使用typeof。typeof只会返回“函数”(我的大小写可能是错误的)。
伊戈尔(Igor)

如果这成为可能,那就太好了。有时,您在将类型从函数中推出时定义了它们,但是没有(很好)的方法来捕获此结构。
约尔根·特维特(JørgenTvedt),

Answers:


162

编辑

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

有关详细信息,请参见此处

TypeScript很棒!


老派骇客

不幸的是,Ryan的答案不再起作用。但是我用一个骇客修改了它,对此我感到不愉快。看哪:

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

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

TypeScript是最好的。:D


52
耶稣,那太可怕了。
John Weisz

对于流:const DUMMY =(((null:any):Object)&& fn()导出类型Type = typeof DUMMY
David Xu

任何想法,为什么当我安装2.8,并尝试我收到以下错误: Cannot find name 'ReturnType'?使用vscode
NSjonas

1
@NSjonas您需要告诉vscode使用其他版本。我认为状态栏位于右下角。
Meirion Hughes

12
我必须做ReturnType<typeof fn>(答案意味着ReturnType<fn>足够了)。
spacek33z

49

TypeScript 2.8中最简单的方法:

const foo = (): FooReturnType => {
}

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

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;

4

无法执行此操作(请参阅https://github.com/Microsoft/TypeScript/issues/6606以了解添加此工作项的工作项)。

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

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

3
我认为这种解决方法不再有效-可能是由于基于控制流的类型分析。
JKillian

3
@JKillian你是对的,示例提出不再起作用,但可以用轻松地欺骗打字稿!1代替false- typescriptlang.org/play/...
DanielM

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)但是IMO只会使呼叫更加混乱。

我只是使用此方法和一些正则表达式查找/替换来迁移一个旧的Angular 1.x项目,该项目最初以JS编写了约1500个工厂函数,并在Foo所有用法中添加了etc类型...会发现。:)


谢谢!虽然很伤心,但是要花这么多钱,但这至少有效!
ecmanaut

@ecmanaut我们不再需要这个了!在TS 2.8中,您可以ReturnType<F>用来获取函数返回类型。:)
亚伦·比尔

此处的答案与问题的示例基础大相径庭,因此很难弄清楚如何产生一种类型,该类型是函数的返回类型test。这个答案是比较有用的一个只重命名test,以foo(诚然产生更复杂的返回类型,踢)。如果您已经知道如何将其应用于原始示例,那么接受的答案和您的评论都可能很棒。(这里已经很晚了,对我来说,完整的ReturnType示例的语法看起来并不立刻。)
ecmanaut

1

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

但是,此方法有一些明显的局限性:

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

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

--emitDecoratorMetadata --experimentalDecorators

0

如果不悲伤地执行它,就无法检索该函数的返回类型。这是因为当TypeScript编译为JS时,您会丢失所有与类型有关的信息。


3
尽管从技术上讲TS在运行时会丢失类型信息,但这并不重要,因为OP希望在编译时确定函数的类型。现在,这ReturnType<T>已经在TypeScript中实现,这更加明显。
dayturns '18

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

1
我认为函数args不需要是通用的,因为无论如何您都将它们扔掉了。fn: (...args: any[]) => Z是你所需要的全部。
亚伦·比尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.