Stop hand-writing your API types

Every hand-written interface for an API response is a small lie waiting to happen. Generate your contracts and make breaking changes fail the build.

Every codebase I’m asked to rescue has the same file. It’s called types.ts, it’s 1,400 lines long, and it’s full of interfaces that describe what the API returned in 2023.

Hand-written API types drift. Not because developers are careless, but because nothing stops them from drifting. The backend renames userId to accountId, the frontend type still says userId, and TypeScript cheerfully approves code that breaks at runtime.

Generate, don’t transcribe

The fix is mechanical: your API schema is the source of truth, and frontend types are generated from it.

  • OpenAPI backend? openapi-typescript turns the spec into types in one build step.
  • GraphQL? graphql-codegen generates typed hooks per query.
  • Own the backend too? Share a Zod schema and infer both the validator and the type from it.
// One schema, three jobs: validation, types, docs
const Job = z.object({
  id: z.string(),
  title: z.string(),
  salary: z.object({ min: z.number(), max: z.number() }).nullable(),
});

type Job = z.infer<typeof Job>;

The payoff

On the Booming project this setup caught a breaking change in CI the same afternoon the backend team shipped it. Before, that bug would have reached production and surfaced as a support ticket three days later.

Generated types stay honest because they cannot drift from the schema. Hand-written ones only describe what you believed when you wrote them.