Code generators · 6 min read
JSON to TypeScript: types that match reality
The fastest way to get correct TypeScript types for an API is to generate them from a response that the API actually returned. Hand-written interfaces describe the payload you expect; a JSON to TypeScript conversion describes the payload you have, and the gap between those two is where runtime crashes live.
Updated
Why hand-written types drift
Interfaces written from documentation or from memory tend to be optimistic. They mark everything present, assume a nullable field is always there, and quietly miss the nested object that only appears on premium accounts. TypeScript then enforces a shape the server never promised, and the first `undefined` surfaces in production rather than at compile time. Generating from real responses inverts the process: the compiler is checking an observed shape instead of a hoped-for one.
Reading the generated file
A useful conversion names nested objects after their keys, keeps array element types intact, and expresses uncertainty explicitly. Watch for the three markers that carry all the meaning:
export interface Order {
id: string;
total: number;
coupon?: string; // absent in some responses
shippedAt: string | null; // present but null until shipped
items: Array<OrderItem>;
}
The difference between `coupon?: string` and `shippedAt: string | null` is not cosmetic. Optional means the key can be missing; null means the key is there with no value. APIs do both, often in the same payload, and conflating them pushes a null check into code that assumed a string.
Use more than one sample
A single response marks everything required. Paste two or three responses — ideally one from an empty account and one from a full one — and the optional keys reveal themselves: a field missing from any sample becomes `?`, and a field that is sometimes null becomes a union with `null`. This is the cheapest correctness upgrade available, and it is the reason generated types should be regenerated when the API changes rather than written once.
Never let a generated interface be the only description of your API. Keep a schema or contract test alongside it, so a server change fails a build rather than a user session.
Where the types belong
- A dedicated `types/` or `api/` folder, not scattered through components.
- One file per endpoint or per resource, with a comment naming the endpoint and the date it was captured.
- A regeneration note: which call produced the payload, so the next person can repeat it.
- An export consumed by both the fetch layer and the components, so a change breaks exactly one place.
Turn on strict mode
Generated types only pay off with `strict` enabled, because that is what makes an optional key an actual error when accessed directly. Pair generated interfaces with `unknown` at the fetch boundary and narrow before use: `JSON.parse` returns `any`, so a cast to the generated interface should be the point where you have validated, not where you hope.
Generate from payloads you would not upload
API responses are the most sensitive JSON most developers handle — account data, orders, tokens. Running the JSON to TypeScript conversion in the browser means the payload is parsed locally and never transmitted, so you can paste a real response without redacting it first, and the tool keeps working offline.
JSON to TypeScript — frequently asked questions
How do I make a generated field optional?
Include a second sample where that key is absent and regenerate — the converter then emits `key?: type`. Inference only marks a field optional when it has evidence of absence, which is why one sample is never enough for a contract.
Should I use interface or type for generated JSON types?
Both work for object shapes; interfaces are conventional for API models because they can be extended and produce clearer error messages. The important choice is `strict` mode, not which keyword you pick.
Can I convert JSON to TypeScript without sending data to a server?
Yes. The converter on this site generates the interfaces in the page itself, so the response never leaves your browser and the conversion continues to work when the network is disabled.
Tools mentioned in this post
Keep reading
5 min read
JSON to Go: structs that unmarshal on the first try
Convert JSON to Go structs with correct field names and json tags, nested types included — plus the numeric, null and time traps to watch.
6 min read
JSON to JSON Schema: from sample payload to contract
Convert JSON to JSON Schema in the browser: infer a draft from a real payload, then harden required fields, formats and enums — plus the limits of inference.
5 min read
JSON to SQL: from a payload to a table you can query
Convert JSON to SQL with CREATE TABLE and INSERT statements generated from a real payload, with sensible type mapping, escaping and honest limits.
- Longer read: JSON to TypeScript: Types That Tell the Truth