Developer

JSON to TypeScript: Generate Types From Sample JSON

JSON to TypeScript in your browser: paste JSON, get interfaces with optional fields, unions, and maps, checked by the compiler. Nothing is uploaded.

Use the JSON to TypeScript: Generate Types From Sample JSON

Options
Paste some JSON to get its TypeScript types

Objects become interfaces, lists of similar objects are joined into one type with optional properties where some are missing, and values that can be more than one thing become unions. Paste several documents, one to a line, to get one type that fits them all.

Everything runs in your browser. What you enter is never uploaded or stored.

Typing out an interface for a large API response by hand is slow and easy to get wrong. This page reads a sample of the JSON and writes the TypeScript type for it: an interface for each object, a list type for each array, a union where a value can be more than one thing, and an optional property where some objects do not have it. When you paste several samples, it makes one type that fits all of them, which is what you need, because a single response rarely shows every field.

The page is strict about what it reads. It tells you the line and column of an error, notices a key written twice, and warns about numbers that are too big or too precise for a JavaScript number, which is where generated types and real data usually part ways. Everything is worked out in your browser, and the code behind the page makes no network requests, so a response with real customer data in it stays on your device.

How to use the JSON to TypeScript: Generate Types From Sample JSON

  1. Paste your JSONPaste one JSON document, or several documents with one on each line. A list of objects is joined into one type, so a full response is better than a single item.
  2. Set the optionsName the main type, choose interface or type, and switch export, readonly, and the example comments as you like. Reusing the same shape and detecting maps are on by default and can be switched off.
  3. Read the notesIf the JSON has a mistake, the page shows the line and column, the line, and what it expected. Warnings appear for duplicate keys and for numbers that JSON.parse would round.
  4. Copy or downloadCopy the types, or download them as types.ts. Then check the optional properties and unions against the API's documentation, since a sample can show only what it contains.

How the type is worked out

Each value gives a type: a string, a number, a boolean, null, a list, or an object. A list gives the type of its items, and the items are joined into one. Joining two objects goes property by property. A property that is in both keeps its type, joined. A property that is in only some of the objects is optional, written with a question mark. Two different types for one property become a union, so a field that is a number in one item and a string in another is typed as string | number.

A list that is empty has no items to learn from, so its type is unknown[], which makes you check the values before you use them, instead of any, which would let mistakes through. A property that is only ever null is typed as null, and one that is null in some items and a string in others is string | null. Because a JSON sample is a handful of examples and not a description, the page cannot know that a field that was always present is truly required. It writes what the sample shows.

Names for the types

The name of a type comes from the key that holds it. The key user_profile gives UserProfile, and a key in a list is made singular, so items gives Item and categories gives Category. A name that is already used for a different shape gets a number, so a user inside owner is User2 when User already exists. A name that clashes with a built-in type, such as Date or Record, gets Type added.

Objects that have exactly the same properties, with the same types and the same optional properties, use one interface by default, so a billing address and a shipping address do not appear twice. Switch this off to get one interface for every place, which some teams prefer so that the two can change on their own.

Maps and IDs

Some JSON uses keys as data: an object that maps user IDs, order numbers, or UUIDs to records. Writing an interface with a property for every key would be useless, because the keys change from one response to the next. When an object has at least five keys and every key looks like an ID, a number, a UUID, a long hex string, or a word with a number such as user_42, the page writes Record<string, T> where T is the joined type of the values. An object whose keys look like words is left as an interface.

Numbers that do not fit

A JavaScript number is a 64-bit floating point number. Number.MAX_SAFE_INTEGER is 9,007,199,254,740,991, and an integer above it can be rounded when it is read. A 19-digit ID that is written as a number in JSON comes out of JSON.parse as a different number. TypeScript's number type cannot help, because the damage is done before the value reaches your code. The page reads the digits of every number itself, and when a number would be rounded it says so, with the line, so that you can ask the API for the ID as a string or read the response with a parser that keeps the digits.

What the page refuses and notices

The reader follows RFC 8259 and ECMA-404. Single quotes, a trailing comma, comments, NaN, undefined, a leading zero in a number, and a line break inside a string are all errors, and each is explained in words with its position. A key that is written twice is not an error in JSON, but the second one wins in JSON.parse and the first is lost silently, so the page lists it. A byte order mark at the start is ignored.

How the types were tested

The reader was compared with JSON.parse on 1,500 random documents, written with and without white space, and on the same documents damaged by one character. It agreed on whether each was valid, and on the values of the valid ones. 3,000 random strings were also read to check that none caused an error.

The types were checked with the TypeScript compiler itself. 600 documents and groups of two to five documents were made at random, with nested objects, lists of similar objects, mixed lists, null, and keys that are not identifiers. A type was made for each, in six different sets of options, and each sample was assigned to its type in strict mode. The compiler accepted every one. As a check that the types are not too loose, 300 samples were changed in one place, a string to a number or a boolean to a string, and the compiler refused at least 97 of every 100.

Limits and accuracy

  • A sample is not a schema. A field that is always present in the sample may be optional in the API, and a string that is always one of three words is typed as string, not as the three words.
  • The page does not turn dates into Date. JSON has no date type, so an ISO date is a string. The option for example comments marks the strings that look like dates.
  • A list is typed by joining its items, never as a tuple, so [1, "a"] is (string | number)[].
  • Types disappear when the program runs. To check data at run time, use a validation library or a JSON Schema, and use these types to describe what the validation accepts.
  • The page reads JSON, not JSON Schema, and it writes TypeScript only. It does not write Zod schemas or classes.
  • A map is recognised by the look of its keys. An object whose keys are meaningful words, such as the days of the week, stays an interface, and one with only a few ID-like keys does too.
  • Very large inputs are slow to type in the browser. The page works on documents of a few megabytes, and the depth of nesting is limited to 500 levels.

Frequently asked questions

How do I convert JSON to TypeScript?

Paste the JSON on this page. Objects become interfaces, lists become array types, and values that can be several things become unions. Copy the result or download it as types.ts. Paste a full response, or several, so that optional fields show up.

Why is a property optional?

Because some of the objects in a list did not have it, or some of your documents did not. The page marks a property with a question mark when it is missing from at least one object that it joined. If one sample is all you have, it cannot know which properties may be missing.

What do I do with a large number or ID that is flagged?

JavaScript cannot keep every digit of an integer above 9,007,199,254,740,991, so JSON.parse rounds it. Ask the API for the value as a string, or read the response with a parser that keeps the digits, and type the field as string.

Can I use several JSON documents?

Yes. Put one document on each line and the page makes one type that fits them all. A list of objects inside one document is joined in the same way. The more varied the samples are, the more accurate the optional fields and unions are.

Should I choose interface or type?

For plain data they work the same. Interfaces can be extended and merged by later declarations, and type aliases can be used in unions and mapped types. Pick the one your project uses, and the page writes the other form for you at any time.

Does it validate my data?

No. TypeScript types are checked when you compile, and they are gone when the program runs. The types describe the shape of the sample. To check real data as it arrives, use a schema validator, and use this page to get started on the shape.

Is my JSON uploaded to a server?

No. The JSON is read and the types are written in your browser, and the code behind the page makes no network requests. Nothing is saved, so copy the result before you close the page.

Research and references

This page was written and checked against the sources below.

  1. RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format
  2. Ecma International: ECMA-404, The JSON Data Interchange Syntax
  3. TypeScript Handbook: Object Types
  4. TypeScript Handbook: Everyday Types
  5. MDN: Number.MAX_SAFE_INTEGER