JSON to TypeScript Converter

Turn a JSON sample into TypeScript interfaces — nested objects named and deduplicated, array shapes merged, optional fields detected — in your browser. Free, no sign-up — runs locally in your browser.

Your work is auto-saved in this browser only, so a refresh won't lose it. Nothing is uploaded.

Why generate types from a sample?

Every API integration starts with the same half hour: someone pastes a JSON response into an editor and hand-writes the TypeScript interfaces that describe it, field by field, guessing at nesting, missing a key that only appears on Tuesdays. A sample is evidence — often the only specification an API actually ships — and the shape of that evidence can be extracted mechanically, completely and without typos. That is what this converter does: paste a representative JSON document and get back the interfaces it implies, ready to paste into your project and argue with. The argument is the valuable part. Generated types are a faithful report of one sample, and the places where they are wrong — an ID that arrived as a number in this response but is a string in another, a field that happened to be null today — are exactly the places where your knowledge of the domain has to take over.

How to use this tool

  1. Paste the JSON. A real API response is ideal; the more representative the sample — including its edge cases, empty arrays and optional blocks — the more truthful the types.
  2. Name the root. Root is fine for a quick look; for code you will keep, use the name the type will wear in your project (UserProfile, OrderResponse).
  3. Press Generate TypeScript. The root interface comes first, the interfaces it references after it.
  4. Read the optionality. Any field marked ? was absent from at least one element of an array in your sample — that is your sample telling you the field cannot be trusted to exist.
  5. Copy or download the result, then tighten it: add the unions, formats and semantics only you know about.

The rules it follows

Naming. Interfaces are PascalCase, derived from the key that holds the object: billing_address becomes BillingAddress, an array under line_items becomes LineItem. Keys that are not legal identifiers (they contain spaces, dashes, or start with a digit) are quoted in the output, exactly as TypeScript requires. Merging. All elements of an array are treated as sightings of one shape: their keys are unioned, the types for each key are unioned, and absence is recorded as optionality. Deduplication. Two objects with the same keys and the same types — wherever they appear in the document — become one interface with one name, referenced from both places; your address object in billing and shipping is one Address, not two copies waiting to drift apart. Honesty about types. JSON's six types map to TypeScript's directly: strings stay string even when they look like dates, numbers stay number, and an empty array is unknown[] because the sample offers no evidence.

Worked example

Given this sample (with one user who has no nickname):

{
  "team": "Platform",
  "users": [
    { "id": 1, "name": "Ada", "nickname": "ada", "admin": true },
    { "id": 2, "name": "Grace", "admin": false }
  ]
}

the converter emits the root first and the merged element shape after it:

export interface Root {
  team: string;
  users: User[];
}

export interface User {
  id: number;
  name: string;
  nickname?: string;
  admin: boolean;
}

Note what the second user taught it: nickname is optional because the data — not a guess — showed it missing. Feed it a sample where every user has one and the ? disappears. The types are only ever as true as the sample you give them, which is the strongest argument for generating from the ugliest real response you can find.

Frequently asked questions

How are nested objects named?

Each nested object becomes its own interface, named in PascalCase after the key that holds it: an object under the key "address" becomes interface Address, and an array under "users" yields interface User (the plural is singularised). Identical shapes — same keys, same types — are deduplicated into one shared interface instead of being re-emitted; two genuinely different shapes that want the same name get a numeric suffix (Address, Address2). The root interface takes the name you give it, Root by default.

When does a field become optional (marked with ?)?

When the evidence says it can be absent. Inside an array of objects, the elements are merged into one shape: a key present in every element is required, a key missing from even one element is marked optional — because the data itself demonstrates both forms. A key that is present but null is not optional; it is typed as its type plus null (for example string | null), which is a different and stronger statement. A single standalone object has no absent keys, so none of its fields are optional.

What happens with arrays that mix types?

The element types are unioned: [1, "two", true] becomes Array<number | string | boolean>, and an array mixing objects with primitives unions the merged interface with those primitives. An empty array offers no evidence at all, so it is typed unknown[] — the honest answer — rather than pretending the elements are strings or numbers you have not seen.

Why aren't date-looking strings typed as Date, or numeric strings as number?

Because JSON has exactly six types — object, array, string, number, boolean, null — and the sample is the only evidence available. A string containing "2026-10-23" might be a date, a version label or a product code; guessing Date would produce interfaces that lie with confidence. The generator reports the shape the JSON actually has. Tightening the types afterwards — swapping in Date, string unions for enums, branded ID types — is the modelling work only you can do, and it is much faster from an accurate skeleton than from a blank file.

My JSON is invalid and it just shows an error. What now?

The converter reports the line and column of the first syntax error, using the same strict scanner as the JSON formatter on this site. Fix that one spot — a trailing comma and a missing quote account for most failures — and convert again. If the text is JSON-shaped but bent (single quotes, unquoted keys), run it through the formatter's Repair first; this converter deliberately accepts only real JSON, so the types it emits are never based on a guess about what you meant.

Related tools

Related guides