Skip to content

JSON to TypeScript Interface Generator (Free, Online)

Convert JSON to TypeScript interfaces or types. Nested objects, merged array types and optional fields detected automatically. Runs in your browser.

By Updated Runs in your browser

JSON to TypeScript guide

Paste a JSON response and get clean TypeScript interfaces: one per nested object, arrays merged across every element, and fields that are missing in some elements marked optional. Copy or download a .ts file.

What this converter actually does

You paste a JSON sample, it walks every value and writes TypeScript that describes it. Strings become string, numbers become number, true and false become boolean, null stays null. Every object gets its own named interface, named after the key it lives under, so an address object becomes an Address interface instead of one giant inline blob.

It is inference from examples, not a schema. The output can only be as good as the sample you give it. If your sample has a field that is sometimes a string and sometimes a number, show both and you get string | number. Show one and you get a type that is wrong half the time.

How arrays and optional fields are detected

This is where most quick converters fall over. They look at the first element of an array and assume every element looks the same. This one merges every element. If an array holds three order objects and only one has a coupon field, the merged Order interface gets coupon?: marked optional, because the field was missing from some samples. A field that shows up in every element stays required.

Types merge the same way. If one order has total: 49.5 and another has total: "12.00", you get total: string | number, which is your cue to go fix the API. Arrays of mixed primitives become unions too: [1, "a"] becomes (string | number)[]. An empty array gives unknown[], because there is nothing to infer from. Add one real element to your sample and it resolves.

Array item names are singularized: an orders array produces an Order interface, categories produces Category, addresses produces Address. When the key is already singular or has no obvious singular, the item type gets an Item suffix, so data becomes DataItem[].

A worked example

Take the preloaded sample. The root object has an orders array with two entries. The first has coupon: null, the second has shippedAt and no coupon. The output is an Order interface with orderId: string, total: number, items: Item[], coupon?: null and shippedAt?: string. Both last fields are optional because neither appears in every order.

coupon?: null looks odd, and it should. It tells you the sample only ever showed null for that field. In the real API it is probably string | null. Edit the generated type by hand, or better, paste a sample where the coupon is actually set. The last-login key has a hyphen, so it is emitted quoted: "last-login": null. Keys that are valid identifiers stay bare.

interface vs type alias

For plain object shapes the two are interchangeable in day-to-day code. Interfaces can be extended and merged across declarations, and editor tooltips show the interface name instead of the full expanded shape, which keeps error messages short. Type aliases are needed for unions and mapped types. The TypeScript handbook's own advice is to use interface until you need a type feature. The default here follows that. Switch to type alias if your codebase lints for one style.

Readonly adds the readonly modifier to every field. Use it for API responses you never mutate, like cached server data or Redux state. It catches accidental writes at compile time and costs nothing at runtime.

Pitfalls that bite in production

Dates are strings. JSON has no date type, so "2026-03-14T09:30:00Z" becomes string. If your code calls .getTime() on it, TypeScript will stop you, which is correct. Parse it at the boundary.

Big integers lose precision. JSON.parse turns 9007199254740993 into 9007199254740992 silently, and the type says number either way. Twitter-style 64-bit IDs should travel as strings. If you see huge numeric IDs in your sample, that is a bug waiting to happen.

Generated types are not validation. They describe what you expect, and TypeScript erases them at runtime. If the API changes shape, your code still compiles and then crashes. For data from outside your control, pair these types with a runtime validator such as Zod or Valibot, or at least a check on the critical fields.

Duplicate names get numbered. If two unrelated objects both live under a key called meta, you get Meta and Meta2. Rename them to something meaningful before committing. Same shape, same name is fine to merge by hand too.

Privacy

API responses carry customer data, tokens and internal IDs. Plenty of converters post your JSON to a server to run the conversion. This one is about 100 lines of JavaScript running in your tab. Open DevTools, watch the Network panel, and paste away. Nothing goes out.

How we calculate: sources

Frequently asked questions

How do I convert JSON to a TypeScript interface?

Paste the JSON into the input box. Interfaces are generated as you type, one per nested object, named after their keys. Set the root name, then copy the output or download it as types.ts.

How are optional fields detected?

When an array holds several objects, all of them are merged. A key that appears in some elements but not all gets a ? and becomes optional. Keys present in every element stay required.

What happens with arrays of mixed types?

Element types are merged into a union, so [1, "a"] becomes (string | number)[]. Arrays of objects merge into one interface. An empty array becomes unknown[] because there is nothing to infer from.

Should I use interface or type?

For object shapes either works. Interfaces can be extended and show shorter names in errors, so they are the default. Pick type alias if your codebase or linter prefers it.

Why is a field typed as null?

Your sample only ever had null for that key. The real type is probably string | null or similar. Paste a sample where the field has a value, or edit the type by hand.

Does it handle keys with dashes or spaces?

Yes. Keys that are not valid TypeScript identifiers, such as last-login or first name, are emitted in quotes so the interface still compiles.

Is my JSON sent to a server?

Everything runs in your browser. Nothing you enter is uploaded to a server or stored by us.

Do generated types validate data at runtime?

No. TypeScript types disappear when compiled. For data from external APIs, pair the types with a runtime validator such as Zod or check critical fields yourself.