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 infersnull— but the real type is probablystring | null. Feed it a populated sample, or fix it by hand. - Empty arrays.
"tags": []infersany[]— 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 itmiddleName?: string. - Unions. A
statusthat’s"active"in your sample becomesstring, not the literal union"active" | "banned" | "pending". Narrow it manually for the safety. - Numbers that are really enums or IDs.
"currency": 840types asnumber; 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.