Obtaining the return type of a function

Solution 1:

EDIT

As of TypeScript 2.8 this is officially possible with 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[]

See this pull request to Microsoft/TypeScript for details.

TypeScript is awesome!


Old-school hack

Ryan's answer doesn't work anymore, unfortunately. But I have modified it with a hack which I am unreasonably happy about. Behold:

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

It works by casting false to the literal value of true, so that the type system thinks the return value is the type of the function, but when you actually run the code, it short circuits on false.

Solution 2:

The easiest way in the TypeScript 2.8:

const foo = (): FooReturnType => {
}

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

Solution 3:

The code below works without executing the function. It's from the react-redux-typescript library (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;

Solution 4:

There isn't a way to do this (see https://github.com/Microsoft/TypeScript/issues/6606 for the work item tracking adding this).

A common workaround is write something like:

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

Solution 5:

Edit: This is not needed with TS 2.8 any more! ReturnType<F> gives the return type. See accepted answer.


A variant on some of the previous answers that I'm using, which works in strictNullChecks and hides the inference gymnastics a bit:

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

Usage:

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; }

It does call the getReturnType function, but it does not call the original function. You could prevent the getReturnType call using (false as true) && getReturnType(foo) but IMO this just makes it more confusing.

I just used this method with some regexp find/replace to migrate an old Angular 1.x project that had ~1500 factory functions written like this, originally in JS, and added the Foo etc types to all uses... amazing the broken code one will find. :)