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
- An async function's return type is always a Promise.
- A generic parameter carries the response shape through.
unknownfrom JSON must be narrowed before use.
Keywords and builtins used here
ApiErrorPromiseStringTasasyncawaitcatchconstfunctionifinterfacenumberparsereturnstringthrowtrytypeunknown
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.
Step 2 of 2 in Async types, step 2 of 8 in Async & modules.