JSON to TypeScript Interface

How to use 3 steps
  1. Paste a JSON sample.
  2. Set the Root interface name and Output style.
  3. Press Generate Types, then Copy.
TypeScript

Types are inferred from one sample, so they describe what that sample contains rather than what the API guarantees. Arrays are merged across every element, which is what makes optional fields detectable; an empty array becomes unknown[] because nothing in the sample says what it holds, and null values become a union with null rather than being dropped. Keys that are not valid identifiers are quoted.

How this tool works

A JSON sample is walked and a TypeScript interface is inferred from what is actually there. Nested objects become their own named types rather than being inlined, so the result reads like something a person would have written. Arrays are examined across all their elements rather than only the first, which is what catches a field that is a string in most records and null in one.

Where the elements of an array disagree, a union type is produced instead of a guess. Keys that are not valid identifiers are quoted, and keys colliding with reserved words are handled. The optional-properties setting marks a field as optional where it is missing from some objects in an array — which is usually closer to the truth than declaring it required and finding out later.

What can and cannot be inferred from a sample

  • A sample is evidence, not a specification: a field that happens to be a string in your sample is typed as a string. If the API can also return null there, only the API's documentation will tell you.
  • Feed it several records rather than one: an array of objects gives the inference something to compare, which is how optional fields and unions are discovered at all.
  • Numbers lose their distinctions: JSON has one number type, so an integer identifier and a decimal price both become number. Narrowing those is a manual job.
  • Dates arrive as strings: JSON has no date type. A field that looks like a timestamp is typed as a string, and converting it is a decision for your code.

A sample is evidence, not a specification

The [msm_tool slug="json-to-typescript"] infers a TypeScript interface from what is actually present in the JSON handed to it, which means a field that happens to be a string in the sample is typed as a string — full stop. If the real API can also return null for that field on some other request, nothing in the sample can reveal that, and only the API's own documentation will.

Feed it several records, not one

An array of objects gives the inference something to compare across, which is the only way optional fields and union types get discovered at all. A single object shows only one version of the shape; comparing many is what reveals that a field is sometimes missing, or sometimes a different type entirely.

Numbers lose their distinctions on the way in

JSON has exactly one numeric type, so an integer identifier and a decimal price both arrive as the same kind of value and both become `number` in the generated interface. Narrowing that back into something more specific is a manual step afterwards, since nothing in a JSON sample carries the distinction to infer from.

Dates arrive as strings, because JSON has no date type

A field that looks exactly like a timestamp is typed as a string regardless, since JSON itself has no native date representation for the inference to detect. Converting that string into an actual date remains a decision made in code, not something the generated type can express on its own.

Nested objects become their own named types

Rather than inlining a nested object's shape directly into its parent, each one is given its own named interface, which reads closer to what a person would actually write by hand and makes the resulting type reusable elsewhere rather than trapped inside a single larger definition.

Where the elements of an array disagree

When different objects in the same array show a field taking different types, the result is a union type rather than a guess at which one is "correct" — both possibilities are represented rather than one being silently discarded. Keys that are not valid identifiers are quoted, and keys that collide with reserved words are handled rather than left to produce invalid TypeScript.

Frequently Asked Questions

Specific to the JSON to TypeScript Interface. Broader questions about this category are answered on the category page.

Because your sample never showed a null. Inference can only describe what it was given — feed it a record where the field is null and it will produce a union.
Many, as an array. Comparing records is how optional fields and union types are detected; a single object cannot show either.
JSON has only one numeric type, so integers and decimals are indistinguishable in a sample. Narrowing that is manual.
They stay strings, because JSON has no date type. Converting them is a decision for your code rather than something inference can make.
No. Each becomes its own named interface, which reads better and lets you reuse the type elsewhere.

Subscribe to receive notifications about new tools, features, and productivity tips.