JSON to TypeScript Converter
Paste JSON and get ready-to-use TypeScript interfaces and types: nested objects, arrays, optional fields, mixed-type unions — generated live, 100% in your browser.
Paste a JSON object (an API response, a config file, a sample payload) and the converter infers a
schema as it goes: every distinct object shape becomes a named interface or
type, fields that are missing in some objects are marked optional with ?,
and values that hold different types across objects become unions like string | number.
Pick your style, rename the root type, and copy the result or download it as a .ts file.
JSON input
Any valid JSON — an object, an array, or a bare value. The conversion updates as you type.
TypeScript output
How the converter works
The converter walks your JSON and builds a schema instead of translating each value one by one. Every object key is tracked across all the objects at that position, so the inferred type reflects what your data actually does — not just the first example it sees:
- Nested objects become named types. The name is derived from the key that holds
the object (
profile: { ... }becomesProfile); array elements are named after the array key (users: [ { ... } ]becomesUser[]). - Optional fields. If a key is present in some objects but missing in others,
it is marked optional:
email?: string. This is the single most useful feature when typing real API responses, where fields come and go. - Mixed types become unions. If the same key holds a string in one object and a
number in another, the field is typed
string | number. The same rule applies to array elements, so["a", 42]becomes(string | number)[]. - Identical shapes are shared. Two objects with the same structure are emitted once and referenced by name, so your types stay DRY.
JSON value → TypeScript type
| JSON | TypeScript | Notes |
|---|---|---|
"text" | string | All JSON strings. |
42, 3.14 | number | JSON has one number type — no integer/float split. |
true / false | boolean | |
null | null | A real value, typed as such (works under strictNullChecks). |
{ ... } | named interface / type | One per distinct shape, named from the key. |
{} | Record<string, unknown> | An empty object tells the converter nothing about the keys. |
[1, 2, 3] | number[] | Element type inferred from every element. |
[] | unknown[] | An empty array has no element type to infer. |
["a", 1] | (string | number)[] | Mixed elements become a union. |
| key missing in some objects | key?: type | Optional-field detection across all objects at that position. |
interface vs type
For plain object shapes both work, and most teams pick one and stay consistent.
interface is the conventional choice for API response shapes: it reads well,
supports declaration merging, and the TypeScript compiler gives slightly better error messages
when an object literal does not match. type aliases are more general — they can
name unions, intersections, tuples and primitives, which is why the converter always uses a
type alias for anything that is not a plain object (a root array, a union, a scalar),
even when you pick the interface style.
Using the output
Download the .ts file (or copy it) into your project and import the types where you
consume the data:
Rename the root type to match your API (the Root type name option), tick
export if the file will be imported from elsewhere, and tick readonly
if the data is never mutated after it is fetched.
⚠️ Things to know
-
JSON has no
undefined. A field is either present or missing; “missing in some objects” is what produces?. If your API sendsnullwhere a value is absent, you will seetype | nullunions — that is the data being faithfully described. - JSON is a tree, not a graph. Recursive structures (linked lists, trees, self-referencing nodes) cannot be represented in JSON, so the converter never emits recursive types.
- One sample is a sample. Optional-field and union detection only see what is in the JSON you paste. If an endpoint can return more shapes than your sample shows, the generated types are a floor, not a ceiling — widen the fields you know vary.
-
Names are best-effort. Keys like
some-keyor123are kept as quoted property names, and type names are derived by PascalCasing the key. Rename anything that reads badly — the output is a starting point, not a contract.