Loading JSON to TypeScript…
Nested objects are named after their key.
Both are structural; pick whichever your codebase uses.
Paste a payload and the types appear beside it.
Every type here is a guess made from one payload. A field present in all three sample orders is written as required even if the fourth order would have omitted it, and a field that is null in the sample is typed null because the sample cannot say what else it holds. Treat the output as a first draft to check against the API contract, not as the contract itself.
Paste a payload — one API response, one fixture, one row from a log — and it comes back as TypeScript declarations you can drop into a file. The top-level object becomes the root interface, and every nested object becomes an interface of its own named after the key that held it, so address becomes Address and lineItems becomes LineItem. Naming them separately rather than nesting anonymous shapes means each one can be imported, extended and referred to by name later.
Two identical shapes are declared once and referenced twice: a payload with from and to objects that both hold lat and lon produces one interface, not two copies. Where two different shapes want the same name, the second becomes Item2 rather than overwriting the first, and keys that are not valid identifiers, such as content-type, are quoted.
Arrays are the part worth getting right, because reading only the first element is how wrong types get generated. Every element is inspected and merged into one shape: a field present in all of them is required, a field present in some is marked optional with a question mark, and a field whose type differs between elements becomes a union. So [{ "id": 1, "coupon": "SAVE10" }, { "id": 2 }] yields id: number and coupon?: string.
A null seen alongside real values is folded in as | null at the end of the union, which reads the way TypeScript developers write it. A mixed array of primitives is bracketed — (number | string | null)[] — because number | string | null[] would mean something quite different. An empty array says nothing about its contents, so it becomes unknown[] with a note explaining why.
A single payload cannot distinguish a field that is always present from a field that merely happened to be present. If all three orders in your sample carry a coupon, coupon is written as required, and the first order without one will fail to typecheck — or worse, will typecheck and be wrong. The reverse is also true: a field missing from one element of a 200-element array becomes optional for all of them, which may be exactly right or may reflect one bad record.
Nulls have the same problem in a smaller way. deletedAt: null can only be typed null, which is useless as a type; the real signature is almost certainly string | null. Every inference of this kind becomes a note under the output, naming the path it came from so you know which line to widen by hand.
JSON has one number type, so 4 and 4.5 are both number and there is no integer to be had. Dates are strings in JSON, so an ISO timestamp arrives as string rather than Date, and a decision about parsing belongs to your code, not to the type. A field whose values come from a fixed set is string, not a union of literals, because a sample cannot know the set. An object with no keys becomes Record<string, unknown>, which is honest, rather than an empty interface that would accept anything.
The interface or type-alias choice is cosmetic here: both are structural, and the difference only matters if you plan to reopen a declaration later, which interfaces allow and aliases do not. No part of the payload is uploaded to produce any of it, which matters when the only sample to hand is a real customer record.
Because at least one element of an array in your sample did not have it. That is a fact about the sample, not about the API. If the missing case was a legitimately incomplete record, delete it from the sample and generate again; if it is real, the documentation is out of date.
JSON has no date type, so "2026-04-01T09:30:00Z" is genuinely a string in the payload. Changing the field to Date would describe something the wire format cannot deliver. Keep it as string and convert at the boundary where you parse the response.
Either works for a plain object shape. Interfaces can be reopened and merged by later declarations and read slightly better in editor tooltips; aliases compose more naturally with unions and mapped types. Pick whichever the surrounding codebase already uses and stay consistent.
Not here — this works one payload at a time. If your API publishes an OpenAPI or JSON Schema document, generate from that instead: a schema states which fields are required, which is exactly the information no sample can supply.