What the generator does
This JSON to TypeScript converter reads one JSON document and writes the interfaces that describe
it, entirely in your browser. Nested objects become their own named interfaces, taken from the key
that held them; arrays of objects are merged into a single shape and the key is singularised, so
users produces a User. Nothing is uploaded, and nothing needs a build step.
You choose the root name, whether declarations come out as interface or type, and whether every
property is marked readonly.
The sample is not the schema
This is the single thing worth understanding before trusting the output. What comes back describes the exact bytes you pasted and makes no claim about the endpoint that produced them.
Three ways that bites. A field that happened to be null in this response is typed null, when the
real contract is almost certainly nullable-and-sometimes-a-string. A field that happened to be absent
from every sampled object simply does not appear. And a numeric field that has only ever held whole
numbers gives you no hint that it is a currency amount with two decimal places waiting somewhere in
production.
Pasting several responses at once helps with the second problem: when a key is present in some
objects of an array and missing in others, it is marked optional with ?, which is exactly the
signal you want. Pasting one lucky response and shipping the result is how a type ends up lying
confidently for six months.
Interface, type alias, and which to reach for
An interface can be declared twice and the declarations merge. That is indispensable when you are
adding a property to something a library exported, and a quiet disaster when two files in your own
project define User and neither author notices. A type alias cannot merge, which makes the
collision an error at the point it happens.
Beyond that, aliases do things interfaces cannot express at all: unions, intersections of computed
shapes, mapped and conditional types. Teams that want one rule rather than two usually land on
type for that reason. Teams that write a lot of ambient declarations land on interface. Neither
choice will be the thing that hurts you.
Why unknown and not any
Every gap in the generated output is filled with unknown: empty arrays, and values the document
never demonstrated. That is deliberate. any silences the compiler everywhere the value travels,
so one unfinished corner of a type quietly disables checking across half a call chain. unknown
does the opposite — it refuses to be used until you narrow it, which keeps the unfinished part of
the model on screen where you can finish it.
The step after this one
Types describe; they do not check. Once the shape is right, put a runtime validator at the boundary where the JSON actually arrives — Zod, Valibot, ArkType, or a hand-written guard for something small. Declare the schema once, infer the TypeScript type from it, and the two can never drift, because there is only one of them. The output here is a good first draft of that schema: the field names and the nesting are already correct, and what you add is the part a sample could never tell you — formats, ranges, and which fields are genuinely optional.
If the payload you are working from is YAML rather than JSON, the JSON to YAML converter goes the other way, and the XML formatter will make an unreadable XML response legible before you decide what to do with it.