Typed Fetch Client With Endpoints
Build a small HTTP client whose methods are typed against endpoint definitions, so request bodies and response shapes are checked at the call site.
Code
export interface Endpoints {
"GET /users/:id": { params: { id: string }; response: { id: string; name: string } };
"POST /users": { body: { name: string }; response: { id: string } };
}
export function createClient(baseUrl: string) {
async function call<
K extends keyof Endpoints,
E extends Endpoints[K],
>(key: K, arg: E extends { body: infer B } ? B : E extends { params: infer P } ? P : never): Promise<E extends { response: infer R } ? R : never> {
const [method, path] = (key as string).split(" ");
const url = baseUrl + path.replace(/:id/, (arg as { id?: string }).id ?? "");
const response = await fetch(url, {
method,
body: method === "GET" ? undefined : JSON.stringify(arg),
});
return (await response.json()) as never;
}
return { call };
}Report a problem with this exampleOpens a pre-filled issue on GitHub.