JSON to TypeScript Converter

Paste a JSON sample and get TypeScript interfaces or type aliases for it — nested objects become their own named types, array elements are merged, and keys missing from some elements become optional.

Copied
JSON Input0 B
TypeScript Output0 B

What this tool does

The converter reads one JSON document and writes TypeScript declarations that describe its shape: an exported root type, plus one named interface (or type) for every distinct kind of nested object. It is a quick way to type an API response or a configuration file without writing the declarations by hand. Everything runs in your browser with the built-in JSON.parse; nothing is sent to a server.

How to use it

  1. Paste JSON into the left pane, or load it with File or URL.
  2. Optionally change Root type name and choose Declare as interface or type.
  3. Click Convert. The declarations appear in the right pane.
  4. Copy the result or Download it as types.ts. Clear empties both panes.

Options

How values map to types

JSONTypeScript
"text", 42, truestring, number, boolean
null (and nothing else at that key)null
"a" in one element, null in anotherstring | null
[1, "a"](string | number)[]
[]unknown[]
{}Record<string, unknown>
A non-empty objectA separate named declaration

Union members always appear in the same order: string, number, boolean, the object type, the array type, then null. All objects found in one array are merged into a single declaration, and a key that is missing from some of them is marked optional with ?. Nested arrays merge the same way, so [[1, 2], ["a"]] becomes (string | number)[][].

Naming rule

A nested object is named after its key in PascalCase: the key is split at every character that is not an ASCII letter or digit, and each part gets a capital first letter, so user_profile, user-profile and userProfile all give UserProfile. Objects inside an array take the key’s name plus Item — items gives ItemsItem, users gives UsersItem — with one more Item per level of nesting. English words are not singularised. A name that would start with a digit gets the prefix Type.

Objects with the same keys, in the same order, with the same types share one declaration, named after the first one found. If two different shapes want the same name, the later one gets a number: Address, Address2. Declarations are listed root first, then in the order they are first reached. Keys that are not valid JavaScript identifiers, such as first-name or 2fa, are written in double quotes.

Worked example

This order record

{
  "id": 1042,
  "status": "shipped",
  "createdAt": "2026-09-14T10:32:00Z",
  "customer": { "name": "Ada Lovelace", "email": "[email protected]" },
  "items": [
    { "sku": "PEN-01", "qty": 2, "price": 1.5 },
    { "sku": "PAD-07", "qty": 1, "price": 4.25, "giftWrap": true }
  ],
  "coupon": null,
  "tags": []
}

produces, with the default options:

export interface Root {
  id: number;
  status: string;
  createdAt: string;
  customer: Customer;
  items: ItemsItem[];
  coupon: null;
  tags: unknown[];
}

export interface Customer {
  name: string;
  email: string;
}

export interface ItemsItem {
  sku: string;
  qty: number;
  price: number;
  giftWrap?: boolean;
}

giftWrap is optional because only the second item has it. coupon and tags show the limits of one sample; you would probably edit them to string | null and string[].

What a sample cannot tell you

Common problems

SymptomCauseWhat to do
“Invalid JSON:” above the panes and “Not valid” in the outputThe input does not parse; the message comes from your browser and differs between browsersFix the line and column shown, or check it in the JSON Formatter
A field is typed unknown[]Every array at that key was emptyAdd a sample with at least one element, or edit the type
A field is typed only nullThe key was null everywhere in the sampleReplace with the real type, e.g. string | null
Too many optional fieldsObjects of different kinds were mergedSplit them into a discriminated union by hand

Frequently asked questions

Is my JSON uploaded anywhere?

No. Parsing and type generation run in JavaScript in your browser, and the page does not send your input to a server. The only request involving your data is the one you trigger with the URL button, which your browser makes directly to the address you enter.

Should I choose interface or type?

Either works: for the object shapes this tool generates, both accept the same values. Interfaces can be extended and merged by redeclaring them, while type aliases can also name unions, so pick whatever your codebase or linter prefers.

Does the output check my data at runtime?

No. TypeScript types are removed at compile time, so a response that does not match goes undetected at runtime. Validate external data separately.

Why is my array of objects one interface with optional keys?

The tool merges all objects in an array into one declaration and marks every key that some elements lack as optional. That accepts the sample, but cannot tell which keys belong together.

Can it read JSON Lines or several documents at once?

No, the input must be a single JSON value. Wrap the records in square brackets and separate them with commas; the root then becomes an array and all records are merged into its item type.

Related tools