typestar

Typing async code in TypeScript

Promise types, awaited results, and typing a fetch wrapper.

interface ApiError {
  status: number;
  message: string;
}

type ApiResult<T> = { data: T } | { error: ApiError };

async function getJSON<T>(url: string,
                          parse: (raw: unknown) => T): Promise<ApiResult<T>> {
  const response = await fetch(url);
  if (!response.ok) {
    return { error: { status: response.status, message: response.statusText } };
  }
  try {
    return { data: parse(await response.json()) };
  } catch (cause) {
    return { error: { status: 0, message: String(cause) } };
  }
}

interface Tour {
  slug: string;
  steps: number;
}

const parseTour = (raw: unknown): Tour => {
  const value = raw as Tour;
  if (typeof value?.slug !== "string") throw new TypeError("bad tour");
  return value;
};

type Loaded = Awaited<ReturnType<typeof getJSON<Tour>>>;
console.log(typeof getJSON, typeof parseTour, {} as Loaded);

How it works

  1. An async function's return type is always a Promise.
  2. A generic parameter carries the response shape through.
  3. unknown from JSON must be narrowed before use.

Keywords and builtins used here

The run, in numbers

Lines
33
Characters to type
797
Tokens
217
Three-star pace
105 tpm

At the three-star pace of 105 tokens a minute, this run takes about 124 seconds.

Type this snippet

Step 2 of 2 in Async types, step 2 of 8 in Async & modules.

← Previous Next →