Turn a JSON Response into a TypeScript Interface in Seconds
You hit a new API endpoint, get back a chunky JSON object, and now you have to describe its shape in TypeScript before your editor will stop complaining. Hand-typing that interface field by field is slow, error-prone, and stale the moment the payload changes. The faster path is to convert json to typescript directly from a real sample: paste the response, copy the generated type, and move on. Drop a payload into the JSON to TypeScript converter and you get a typed interface back instantly.
Try the JSON to TS toolGenerate TypeScript interfaces from a JSON sample, with nested types, arrays and optional fields. Runs in your browser.Why hand-typing API response types wastes time
A typical REST response has a dozen or more fields, several of them nested. Transcribing each key, guessing its type, and matching the casing exactly is the kind of mechanical work that humans are bad at and machines are good at. You will fat-finger a field name, type a number as a string, or forget that one property is itself an object with five more keys inside it. Every mistake surfaces later as a type that silently disagrees with reality.
A generator reads the actual data and infers a type from it. Because the input is a concrete value, the output reflects exactly what the server sent for that request, not what you remembered from the docs. That makes it a reliable starting point, which you then refine by hand where the sample is thin.
From a sample payload to an interface
Start with a single representative response. Suppose your endpoint returns a user record:
{
"id": 4821,
"name": "Ada Lovelace",
"email": "ada@example.com",
"isActive": true,
"roles": ["admin", "engineer"],
"profile": {
"bio": null,
"joined": "2026-01-14"
}
}A converter turns that into a TypeScript interface like this:
interface User {
id: number;
name: string;
email: string;
isActive: boolean;
roles: string[];
profile: Profile;
}
interface Profile {
bio: string | null;
joined: string;
}Three things happened automatically. Each scalar got mapped to its TypeScript primitive (number, string, boolean). The nested profile object became its own named interface rather than an inline blob. And the array of strings became roles: string[]. That is the bulk of the work done in one paste.
interface vs type
Most generators emit interface by default, and for object shapes that is the conventional choice. An interface can be extended and merged, and it reads cleanly for the record-like data that APIs return. Use a type alias when you need something an interface cannot express directly: a union (string | number), a tuple, a mapped type, or an alias for a primitive. For a plain response object, interface User and type User are interchangeable in practice, so pick one and stay consistent across your codebase. The official TypeScript handbook on object types covers both forms and when each fits.
Optional fields, nullables, and unions
A single sample only shows you one snapshot. The hard part of typing a real API is everything the sample does not show, and this is where you have to think rather than paste.
- Nullable vs optional are different. bio: null in the sample produces bio: string | null, meaning the key is always present but may hold null. If a key can be absent entirely, you want bio?: string instead. JSON cannot represent an absent key, so a generator cannot tell these apart from one sample; you decide based on the API contract.
- Inconsistent samples create unions. If one record has "score": 90 and another has "score": "N/A", the honest type is score: number | string. Feed multiple samples in and a good converter will union the observed types rather than picking one and discarding the other.
- Enums hide in strings. A status field that is always "active", "pending", or "closed" is better typed as a union of string literals than as a bare string. The generator sees only string; you tighten it by hand once you know the allowed set.
Nested objects and arrays
Real payloads nest. A converter walks the tree and names a fresh interface for each distinct object shape, then references it from the parent. An array of objects becomes Item[], with Item generated from the first element (or unified across all elements). This recursion is exactly the part that is most tedious by hand and most reliable when automated.
| JSON value | Inferred TypeScript |
|---|---|
| 42, 3.14 | number |
| "hello" | string |
| true / false | boolean |
| null | null (often part of a union) |
| ["a", "b"] | string[] |
| [ {…}, {…} ] | Item[] (named interface per shape) |
| { nested: {…} } | a separate named interface |
One edge case worth knowing: an empty array [] gives the generator nothing to infer from, so it usually falls back to never[] or any[]. Annotate those by hand. Likewise a heterogeneous array such as [1, "two", true] yields (number | string | boolean)[], which is rarely what you actually want; it is a hint that the data is poorly shaped or that you grabbed an unrepresentative row.
Where one sample stops being enough
A generated interface is a strong first draft, not a contract. The type describes the bytes you happened to receive, and the compiler will then trust it completely, even though nothing at runtime guarantees the next response matches. That gap is the source of the most confusing bugs: TypeScript says the field is a number, the server sends null, and your code crashes on a type the compiler swore was impossible.
The practical workflow is two-step. Use the converter to generate the interface in seconds, then either keep it as a plain type for internal data you trust, or, for anything coming off the wire, port it into a zod schema and parse responses through it. The generated interface saves you the transcription; the runtime validator saves you the 2 a.m. incident.
- Grab one or more real responses from the endpoint.
- Paste them into the converter to get a typed interface.
- Fix nullables, optionals, and string-literal unions by hand using the API docs.
- For network data, mirror the type as a runtime schema and parse every response through it.
If your sample will not parse in the first place, clean it up with the JSON formatter before converting, since a generator needs valid JSON to read the shape correctly.
Generate a TypeScript interfaceGenerate TypeScript interfaces from a JSON sample, with nested types, arrays and optional fields. Runs in your browser.Related articles
Pretty-Print vs Minify: When to Format JSON and When to Compress It
When to format JSON for readable diffs and debugging, when to minify it for size, and how to do both privately in your browser.
YAML vs JSON: Which One Should Your Config Use?
YAML vs JSON compared for config files and APIs: syntax, comments, the Norway problem, indentation traps, TOML, and lossless conversion.
Why Is My JSON Invalid? How to Find and Fix the Error
The six mistakes that break JSON, how to read a parser error, and how to fix invalid JSON fast.