Generate TypeScript Types from JSON (and Where Auto-Generators Trip Up)

You have a JSON API response and you want TypeScript interfaces for it. Here’s how to generate them fast — and where the auto-generators quietly get it wrong.

The fast path

Paste your JSON, get interfaces:

{ "id": 1, "name": "Ada", "roles": ["admin"], "profile": { "active": true } }
interface Root {
  id: number;
  name: string;
  roles: string[];
  profile: Profile;
}
interface Profile {
  active: boolean;
}

The JSON to TypeScript converter does this in your browser, nesting objects into their own interfaces.

Where generators trip up

A generator only sees the one sample you give it, which causes predictable gaps:

  • Nullable fields. If your sample has "avatar": null, the generator infers null — but the real type is probably string | null. Feed it a populated sample, or fix it by hand.
  • Empty arrays. "tags": [] infers any[] — the element type is unknowable from an empty array.
  • Optional fields. A field missing from your sample won’t appear at all. If the API sometimes omits middleName, mark it middleName?: string.
  • Unions. A status that’s "active" in your sample becomes string, not the literal union "active" | "banned" | "pending". Narrow it manually for the safety.
  • Numbers that are really enums or IDs. "currency": 840 types as number; you may want an enum or branded type.

When to use a schema instead

If the JSON has a JSON Schema or OpenAPI spec, generate types from that (for example with json-schema-to-typescript or openapi-typescript) — it encodes nullability, optionality and unions the raw sample can’t. Sample-based generation is for quick throwaway typing; schema-based is for anything you’ll maintain.

Rule of thumb

Generate from a sample to skip the boilerplate, then read every field — the generator gives you a draft, not a contract. Nullability and optional fields are where the runtime bugs hide.

Related articles