GGistDev

Async/Await in TypeScript

Type precise async code with Promise<T>, async functions, and safe error handling.

Promise basics

function fetchJson(url: string): Promise<unknown> {
  return fetch(url).then(r => r.json());
}

Annotate the resolved type when known:

interface User { id: number; name: string }
async function getUser(id: number): Promise<User> {
  const r = await fetch(`/api/users/${id}`);
  if (!r.ok) throw new Error("bad status");
  return r.json() as Promise<User>;
}

async/await and error handling

async function run() {
  try {
    const u = await getUser(1);
    console.log(u.name);
  } catch (e: unknown) {
    if (e instanceof Error) console.error(e.message);
  }
}

Enable useUnknownInCatchVariables for safer catch typing.

Concurrency patterns

async function both(a: Promise<number>, b: Promise<number>) {
  const [x, y] = await Promise.all([a, b]);
  return x + y;
}

async function first<T>(ps: Promise<T>[]) {
  return Promise.race(ps);
}

Prefer allSettled when each promise must be accounted for even on failures.

Top-level await

Supported in ESM. Configure module: ESNext and compatible bundler/Node. Exported types remain synchronous; be mindful in libraries.

Summary

  • Type promises precisely; prefer async/await with try/catch
  • Use Promise.all for concurrency; consider allSettled vs race
  • Configure ESM for top-level await where needed