Nimble Toolbox

JSON to TypeScript interfaces

Paste a JSON response and the TypeScript for it appears as you type. Nested objects get their own named types, and nothing you paste leaves this tab.

How to use it#

  1. Paste a JSON sample into the box above, such as a response from the API you are calling.
  2. Give the type a name, and choose whether to declare interfaces or type aliases.
  3. Tick export, readonly fields, or semicolons to match the code it is going into.
  4. Copy the TypeScript from beside the result, or download it as a .ts file.

How the types are worked out#

Every value becomes the type it holds: text is string, any number is number, true and false are boolean, and null is null. An object becomes an interface of its own, named after the key it sits under, so a shipping_address key produces a ShippingAddress interface. The root takes the name in the box.

Arrays are typed by what is in them. An array of objects is read as one type: every element is merged, so a key present in some elements and missing from others comes out optional, and a key that holds a number in one element and a string in another comes out as string | number. The element type is named after the key in the singular, so users holds User.

Two objects with exactly the same keys and types share one interface rather than getting two copies. When two different shapes would take the same name, the second is numbered.

What a sample cannot tell you#

The types describe the JSON you pasted, not every response the API could send. A field that happened to be null in the sample is typed as null, when in other responses it may hold a string. An empty array is typed as unknown[], because there is nothing in it to go on. A key that is always present in your sample comes out required even if the API sometimes leaves it out.

The more varied the sample, the better the types. Pasting an array of several real records, including one with the awkward fields filled in, gives the merger enough to work out which keys are optional and what the nulls stand in for. Read the result against the API documentation before relying on it, and widen anything the sample was too narrow to show.

Types at compile time, validation at run time#

An interface tells the compiler what shape to expect. It does not check anything when the code runs, so a response that does not match still arrives and fails later, somewhere less obvious. That is fine for data you control and risky for data from a third party.

Where the input is untrusted, use a validator written in a runtime schema library, and let the validator produce the type. The JSON to Zod page writes that validator from the same sample, with the type inferred from it. The output here gets you the field names and the rough shape in seconds, which is most of the typing work.

The same sample also gives Go structs or C# classes, when the other end of the API is written in one of those.

Frequently asked questions#

Should I use an interface or a type?

#

For object shapes like these, either works and the compiler treats them almost the same. Interfaces can be extended and merged, and their names show up more clearly in error messages. Type aliases can also name unions and arrays. Use whichever your codebase already uses. A root that is an array or a plain value is always written as a type alias, since an interface can only describe an object.

Why is a field typed as null?

#

Because it was null in the sample, and nothing else was seen in that position. Change it to the real type with | null after it, such as string | null. Pasting an array of several records where that field is filled in for some of them fixes it automatically.

How are optional fields decided?

#

Only across the elements of an array. When objects in the same array have different keys, a key missing from any of them is marked with a question mark. A single object has nothing to compare against, so all of its keys come out required.

What happens to keys that are not valid names in TypeScript?

#

They are quoted. A key such as first-name or 2fa is written as "first-name" or "2fa", which TypeScript accepts as a property name. The type named after such a key is made into a valid name, so first-name gives FirstName.

Is the JSON I paste sent anywhere?

#

No. It is parsed and typed in this browser tab as you type. A real API response with customer records in it can be pasted here safely.