Awaited<Type>
Unwraps a type the way await does, recursively resolving nested promises and thenables.
type Awaited<T> = T extends null | undefined ? T : T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ? (F extends ((value: infer V, ...args: infer _) => any) ? Awaited<V> : never) : T;- Added in TypeScript 4.5
Parameters
| Parameter | Type | Description |
|---|---|---|
$T | any type | The type to unwrap. Usually a `Promise<...>` or the return type of an async function, but any type is accepted. |
Return value
The fully unwrapped value typeThe type `await` would produce for a value of `T`: promises and thenables unwrapped recursively, everything else returned unchanged.
Errors
Nothing at the type level, but a thenable whose `then` callback is not a function type resolves to `never`, which usually surfaces later as an unassignable value.
Changelog
- PHP 4.5Introduced alongside improved inference for `Promise`, `await`, and `Promise.all`, whose signatures in the lib now use it.
Awaited answers one question: what do I actually get when I await this? An async function that returns Promise<T> gives you T; one that returns Promise<Promise<T>> still gives you T, because await keeps unwrapping until the value is not a thenable. The type mirrors that behaviour exactly.
Reach for it whenever you need to name the resolved value of something you did not declare yourself. The canonical form is Awaited<ReturnType<typeof loader>>, which extracts the data type out of an async function without exporting a separate interface, and survives refactors of the function body. Framework users hit this constantly: the payload type of a route loader, a query function, or a generated API client is often only discoverable through its return type.
Why not just write your own
The naive version, T extends Promise<infer U> ? U : T, unwraps exactly one level and knows nothing about non-Promise thenables. Awaited recurses, handles unions by distributing over each member, and passes null and undefined straight through. That is why Promise.all and the type of the await operator itself are defined in terms of it in the standard library.
On a plain, non-promise type it is a no-op, so wrapping a value that might or might not be async is always safe.
Example
When to use it
- Name the payload type of an async loader with `Awaited<ReturnType<typeof load>>`.
- Type a cache that stores resolved values keyed by the promises that produced them.
- Write a helper generic over `T` that works with both a value and a promise of that value.
Frequently asked questions
How do I get the type a promise resolves to?
Write `Awaited<typeof myPromise>`, or `Awaited<ReturnType<typeof myAsyncFn>>` for a function. It unwraps every nested layer, so `Promise<Promise<string>>` resolves to `string` rather than `Promise<string>`.
What is the difference between Awaited<T> and T extends Promise<infer U> ? U : T?
The hand-rolled conditional peels exactly one layer and only recognises the `Promise` type itself. `Awaited` recurses until the type is no longer thenable and matches any object with a compatible `then` method, which is why the standard library uses it for `await` and `Promise.all`.
Does Awaited do anything to a non-promise type?
No — it returns the type unchanged, and `null` and `undefined` pass straight through. That makes it safe to apply to a generic parameter that may or may not be a promise.
More examples
Extracting the data type out of an API client
No `Order` interface is ever declared by hand — the shape is read straight out of the async method, so adding a field to the returned object immediately makes it available on `Order`. The log prints `A-1001: 2 items, 24.50`.
const api = {
async getOrder(id: string) {
return { id, total: 24.5, items: ["mug", "beans"] };
},
};
type Order = Awaited<ReturnType<typeof api.getOrder>>;
function summarize(order: Order): string {
return `${order.id}: ${order.items.length} items, ${order.total.toFixed(2)}`;
}
const order: Order = await api.getOrder("A-1001");
console.log(summarize(order));Writing a helper that accepts a value or a promise
`Awaited<T>` is what makes the return type honest: if a caller passes an already-promised value, the result is not `Promise<Promise<X>>` but the flat resolved type. Output is `1 two [ true, 4 ]` followed by `number string` — the same code path handles both sync and async inputs.
type MaybePromise<T> = T | Promise<T>;
async function normalize<T>(input: MaybePromise<T>): Promise<Awaited<T>> {
return (await input) as Awaited<T>;
}
const a = await normalize(1);
const b = await normalize(Promise.resolve("two"));
const all = await Promise.all([normalize(true), normalize(Promise.resolve(4))]);
console.log(a, b, all);
console.log(typeof a, typeof b);
Discussion