TypeScript Awaited<T> Utility Type Explained

Learn how Awaited<T> recursively unwraps Promise types. Examples for async function return types, nested promises, and Promise.all typing.

Union Types

Detailed Explanation

Understanding Awaited

Awaited<T> models the behavior of await or Promise.then(). It recursively unwraps nested Promise types to get the final resolved value type. Added in TypeScript 4.5.

Basic Examples

type A = Awaited<Promise<string>>;
// Result: string

type B = Awaited<Promise<Promise<number>>>;
// Result: number (recursively unwrapped)

type C = Awaited<string>;
// Result: string (non-Promise passes through)

With Async Functions

async function fetchUser(): Promise<{ id: number; name: string }> {
  const res = await fetch("/api/user");
  return res.json();
}

type User = Awaited<ReturnType<typeof fetchUser>>;
// Result: { id: number; name: string }

With Promise.all

type Results = Awaited<ReturnType<typeof Promise.all<
  [Promise<string>, Promise<number>, Promise<boolean>]
>>>;
// Result: [string, number, boolean]

Practical Pattern: Generic Async Wrapper

async function withRetry<T extends Promise<unknown>>(
  fn: () => T,
  retries: number
): Promise<Awaited<T>> {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn() as Awaited<T>;
    } catch (e) {
      if (i === retries - 1) throw e;
    }
  }
  throw new Error("Unreachable");
}

Before Awaited (pre-4.5)

Before Awaited existed, you had to write manual unwrapping:

type UnwrapPromise<T> = T extends Promise<infer U> ? UnwrapPromise<U> : T;

Use Case

Use Awaited<T> when you need the resolved type of a Promise, especially when working with ReturnType of async functions, generic async utilities, or when dealing with APIs that return nested Promises.

Try It — TypeScript Utility Types

Open full tool