What this does
Paste a JSON value on the left and get a set of TypeScript interface declarations on the right, regenerated about a tenth of a second after you stop typing. It's a pragmatic generator, not a full inference engine: types come from one sample, names come from the keys. Parsing and emitting both happen in your browser, so pasting a real production payload is safe.
How do I generate an interface from an API response?
- Copy one response body out of your network tab or
curl. - Paste it into the JSON panel — the output appears immediately.
- Change Root name from
Rootto whatever the type should be called; blank falls back toRoot. - Copy types puts the whole block on your clipboard, ready to paste into a
.d.ts.
{
"id": 1,
"name": "Ada",
"roles": ["admin", "editor"],
"profile": { "age": 36, "city": "London" }
}
→
interface Root {
id: number;
name: string;
roles: string[];
profile: Profile;
}
interface Profile {
age: number;
city: string;
} How does it name the generated interfaces?
From the key that holds the value, PascalCased with punctuation removed — profile gives Profile, billing_address gives BillingAddress. For an array, the key is singularised by chopping a trailing s, so users yields User[]. That rule is deliberately crude and it shows: boxes becomes Boxe[] and children stays Children[]. Duplicate names get a numeric suffix (User, User2). The root interface is always emitted first; the rest follow.
How are optional keys, nulls and mixed arrays typed?
When an array holds objects, every element is merged into one interface rather than producing a type per element. A key present in only some elements is marked optional, so [{"a":1},{"a":2,"b":"x"}] gives a: number and b?: string. Values of differing types are unioned in first-seen order, with objects first and null appended last: [1,"a",true] becomes (number | string | boolean)[] and [1,null] becomes (number | null)[]. Keys that aren't valid identifiers are quoted, so data-id is emitted as "data-id": number.
Why is a nullable field typed as just null?
Because a single sample where the value is null carries no other information — {"deletedAt": null} can only be typed deletedAt: null. The same blind spot applies to [], which becomes unknown[], and to {}, which gets an empty interface of its own. Widen these by hand to string | null, Tag[] and so on, or paste a richer sample that includes a populated value.
Why do two identical shapes produce two interfaces?
There's no structural deduplication. {"from":{"lat":1,"lng":2},"to":{"lat":3,"lng":4}} emits both From and To with the same body, because naming follows keys rather than shapes. Collapse them into one Point after copying. Likewise, a root-level array gets a type alias plus a generated element interface — type Root = Root2[]. Setting the root name to the plural you actually mean fixes this: Users produces type Users = User[].
What can't be inferred from a single sample?
Literal and enum types (a status field only ever seen as "active" is typed string), date strings, integers versus floats, values that exceed the safe integer range, and any key the server omits when it happens to be empty. Treat the output as a starting draft you tighten by hand. If the JSON won't parse you'll get the browser's own message with the character offset — run it through the JSON formatter and validator first. Related: CSV to JSON for tabular sources and JSON ↔ YAML ↔ TOML for config files.