Guide
How to Generate TypeScript Types from JSON
Writing TypeScript interfaces by hand for every API response is tedious and easy to get wrong. Generating them from a sample payload is faster and more accurate. This guide shows how the generation works, what it does well, and where you still need judgment.
From a sample to an interface
The generator reads a JSON sample and infers a type from what it sees: the field names, the type of each value, and the shape of nested objects and arrays.
{
"id": 42,
"name": "Ada",
"roles": ["admin", "editor"],
"active": true,
"profile": { "bio": "Engineer", "avatar": null }
}produces:
interface Root {
id: number;
name: string;
roles: string[];
active: boolean;
profile: Profile;
}
interface Profile {
bio: string;
avatar: null;
}Nested objects become their own named interfaces, and arrays become typed arrays. That is most of the work done for you in one step.
Inference is only as good as the sample
This is the key thing to understand. The generator only sees the payload you give it. If a field happens to be present and non-null in your sample, the inferred type will say it is always a string, even if the API sometimes omits it or returns null.
Look at the avatar field above. It was null in the sample, so the inferred type is null, which is almost certainly not what you want. The real type is probably string or null. The fix is to feed the generator a sample that shows the field's full range of values, or to adjust the generated type afterward.
Optional and nullable fields
Two situations need attention because a single sample cannot express them on its own:
- A field that is sometimes missing should be optional, written as name?: string.
- A field that is sometimes null should be a union, written as avatar: string | null.
If your API documents which fields are optional, use that as the source of truth and tighten the generated interface to match. Generation gives you a correct starting point for the common case and saves the typing. You still confirm the edges.
Generate it
- Paste a representative JSON response into the schema tool, ideally one with the fields you care about filled in.
- Choose TypeScript as the output.
- Review the interfaces, paying attention to any field that was null or looks too narrow.
- Copy the result into your project and adjust optional or nullable fields as needed.
Why this beats hand-writing types
Beyond speed, generated types stay honest to the data. When you hand-write an interface from documentation, it drifts as the API changes. Regenerating from a fresh response takes seconds and shows you exactly what the payload looks like now. It is a quick way to catch a field that was renamed or a type that changed under you.
The same tool can produce a JSON Schema, Zod validators, and structs for other languages from the same sample, so the contract stays consistent across your stack.
FAQ
Why did a field come out as the wrong type?
Inference only sees your sample. A field that was null or absent in the sample cannot be inferred correctly. Provide a sample that shows the field's real values, or adjust the generated type.
How do I mark a field as optional?
A single sample cannot tell the generator a field is sometimes missing. Add the ? modifier yourself, for example name?: string, based on what the API actually returns.
Can I generate more than TypeScript from the same JSON?
Yes. The same sample can produce JSON Schema, Zod, Go, Rust, Java, Kotlin, and Pydantic, all from the same inferred shape so they agree with each other.