ReturnType<Type>
Extracts the return type of a function type, so a value type can be derived instead of duplicated.
type ReturnType<Type extends (...args: any) => any> = Type extends (...args: any) => infer R ? R : any- Added in TypeScript 2.8
Parameters
| Parameter | Type | Description |
|---|---|---|
$Type | (...args: any) => any | A function type, normally written `typeof someFunction`. For an async function this is the `Promise<T>`, not `T`. Passing a non-function type fails the constraint. |
Return value
The declared or inferred return type of the functionThe function's return type. For overloads, the return type of the last signature. `any` if Type is `any`; `never` if Type is `never`.
Errors
A type argument that is not a function type errors with "Type 'X' does not satisfy the constraint '(...args: any) => any'" and falls back to `any` — including the bare `Function` type, which has no call signature.
Changelog
- PHP 4.5`Awaited<T>` shipped, making `Awaited<ReturnType<typeof asyncFn>>` the standard way to reach the resolved value type of an async function.
ReturnType pulls the return type out of a function type using infer. Its real value is in the direction of dependency: instead of declaring an interface and annotating a function to match it, you write the function and derive the type from it, so the two cannot drift apart.
When to reach for it
- Inferred object returns. A factory or selector returns an object literal you never named;
ReturnType<typeof makeSession>names it. - Redux-style stores.
type RootState = ReturnType<typeof rootReducer>is the canonical pattern — the state type follows the reducer. - Wrappers. Paired with
Parametersto give a higher-order function the exact signature of what it wraps.
What trips people up
It needs typeof. ReturnType<createSession> is an error, because createSession is a value. Write ReturnType<typeof createSession>.
Async functions give you the promise. ReturnType<typeof fetchUser> is Promise<User>. Wrap it: Awaited<ReturnType<typeof fetchUser>>.
Overloads resolve to the last signature, silently.
A failed constraint yields any, not never, which is worse — the error is reported at the type argument, but if it is suppressed everything downstream becomes unchecked.
Example
When to use it
- Name the type of an object literal returned by a factory without writing the interface twice.
- Derive a store's state type from its reducer, as in `type RootState = ReturnType<typeof rootReducer>`.
- Type the result slot of a cache or wrapper alongside `Parameters` for the arguments.
Frequently asked questions
How do I get the return type of a function in TypeScript?
Use `ReturnType<typeof fn>`. The `typeof` is required because type arguments take types, and a function declaration's name is a value.
Why does ReturnType give me Promise<T> instead of T?
Because an async function's return type genuinely is `Promise<T>`. Wrap it as `Awaited<ReturnType<typeof fn>>`, available since TypeScript 4.5, to unwrap the promise.
Does ReturnType work on overloaded functions?
It resolves to the return type of the last overload signature only. Conditional-type inference picks a single call signature, so earlier overloads are ignored.
More examples
State type derived from a reducer
Prints `2 (inc)` and then `{ count: 2, lastAction: 'inc' }`. `State` is never written out by hand: add a field to the object the reducer returns and every selector typed against `State` sees it immediately, whereas a hand-maintained interface would have silently gone stale.
function counterReducer(
state = { count: 0, lastAction: "none" },
action: { type: "inc" } | { type: "dec" }
) {
switch (action.type) {
case "inc": return { count: state.count + 1, lastAction: "inc" };
case "dec": return { count: state.count - 1, lastAction: "dec" };
}
}
type State = ReturnType<typeof counterReducer>;
function selectLabel(state: State): string {
return `${state.count} (${state.lastAction})`;
}
let state: State = counterReducer(undefined, { type: "inc" });
state = counterReducer(state, { type: "inc" });
console.log(selectLabel(state));
console.log(state);Async returns and the Awaited pairing
Prints `is a promise: true` and then `{ id: 'u1', name: 'Ada', roles: [ 'admin' ] }`. The two aliases show the distinction: `ReturnType` gives back exactly what the function returns, which for an `async` function is always a promise. `Awaited` (TypeScript 4.5+) unwraps it, recursively, and is what you want whenever the type is meant to describe the value the caller ends up holding.
async function fetchUser(id: string) {
return { id, name: "Ada", roles: ["admin"] };
}
type Raw = ReturnType<typeof fetchUser>; // Promise<{...}>
type User = Awaited<ReturnType<typeof fetchUser>>; // the resolved object
const pending: Raw = fetchUser("u1");
console.log("is a promise:", pending instanceof Promise);
const user: User = await pending;
console.log(user);
// const wrong: User = fetchUser("u2");
// -> Type 'Promise<...>' is not assignable to type '{ id: string; ... }'
Discussion