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. :)