Skip to content
T
Tools.Town
Free Online Tools for Everyone
Data Tools

JSON to TypeScript: How Type Inference Works

Learn how a JSON sample becomes TypeScript interfaces — how types are inferred, how nested objects and arrays are handled, and the edge cases to watch for.

24 June 2026 4 min read By Tools.Town Team Fact Checked

Key Takeaways

  • Yes, and it's the normal approach
  • Both work for object shapes
  • Objects in the same array are merged into one interface

Why generate types from JSON?

TypeScript’s value comes from knowing the shape of your data. The moment a value is typed any, the compiler stops helping you — no autocomplete, no checks, no refactoring safety. Yet the data you most want typed often arrives as JSON: API responses, configuration files, webhook payloads, and exported records. Writing interfaces for those by hand is slow, and it drifts out of sync the moment the data changes.

Generating types from a real JSON sample flips the work around. Instead of describing the data from memory, you let a representative example define the shape, and you get compile-ready interfaces in seconds. The JSON to TypeScript tool does exactly this in your browser. This guide explains how the inference works so you can trust the output and know where to refine it.

The core idea: walk the value, map each node

JSON has a small, well-defined set of value types: objects, arrays, strings, numbers, booleans, and null. TypeScript has direct equivalents for the primitives, plus interfaces for object shapes and T[] for arrays. Type inference is really just a recursive walk that maps each JSON node to its TypeScript counterpart.

The rules are intuitive:

  • A string becomes string, a number becomes number, a boolean becomes boolean.
  • null becomes the null type.
  • An object becomes a named interface, with each key turned into a property.
  • An array becomes an element type followed by [].

Because the walk is recursive, nesting falls out naturally: an object inside an object produces a nested interface, an array of objects produces an array of a generated interface, and so on to any depth.

Naming nested interfaces

A flat object is easy — one interface with a few properties. Real data is rarely flat, so the interesting question is what to call the interfaces for nested objects. The convention the tool follows is to name each nested interface after the key that holds it, converted to PascalCase. A profile object becomes a Profile interface; an address becomes Address.

When the same name would be generated twice, the tool appends a number to keep every interface name unique, so the output always compiles. You can rename anything afterwards — generated names are a starting point, and a quick find-and-replace in your editor tidies them to your taste. If you want to inspect the structure before generating types, running the sample through a JSON formatter first makes the nesting easy to see.

Arrays: the part that needs judgement

Arrays are where naive generators get it wrong. There are two cases worth understanding.

Arrays of primitives are simple: ["a", "b"] is string[], [1, 2, 3] is number[]. If the elements are of mixed types — say [1, "two", true] — the tool produces a union element type, (number | string | boolean)[], so every element is covered.

Arrays of objects require merging. Consider this:

{
  "users": [
    { "id": 1, "name": "Asha" },
    { "id": 2, "name": "Ravi", "admin": true }
  ]
}

A weak generator infers the element type from the first object only and misses admin. The JSON to TypeScript tool instead merges every object in the array: id and name appear in both, so they’re required, while admin appears in only one, so it becomes optional (admin?: boolean). The result is a single User interface that genuinely describes every element.

The optionality edge case

Inference can only see what’s in your sample, and this matters most for optionality. If a field is sometimes absent, your sample must include an object that omits it for the tool to mark it optional. Likewise, a field that’s sometimes null will only be typed as null if a null appears in the sample.

The practical takeaway: use a representative sample, not the happy-path minimum. If an API sometimes omits a field or returns null, include an example that shows it. When you can’t, generate the types and then add the ? or | null yourself — the generated output is a fast first draft, not a contract.

Empty arrays and unknowable values

What type is []? There are no elements to infer from, so the honest answer is “could be anything.” The tool emits any[] by default, or unknown[] if you enable the safer option. unknown forces you to narrow the type before using elements, which is stricter and often what you want in a well-typed codebase. Either way, an empty array is a signal to supply a better sample or annotate the element type manually.

Interface vs type, and other output choices

The generator lets you tune the output to match your project:

  • Interface or type alias. Emit interface User { ... } or type User = { ... }. Interfaces support declaration merging; type aliases compose more flexibly with unions. For plain data models, both are fine.
  • Export keyword. Toggle export on so the types are importable across modules, or off for local use.
  • Semicolons. Match your formatter’s style so the output drops in without reformatting.
  • unknown over any. Prefer unknown for stricter handling of empty arrays and unknowable values.

These are cosmetic in the sense that they don’t change the inferred shapes — they make the output fit your conventions so you paste it in without friction.

A realistic workflow

Here’s how this fits a normal development loop. You hit an API endpoint and copy a real response. You paste it into the JSON to TypeScript tool, set a meaningful root name like OrderResponse, and copy the generated interfaces into your types file. You then refine: mark fields optional that the sample didn’t reveal, rename a nested interface or two, and add a | null where the API can return null. Total time: under a minute, versus the ten or fifteen it takes to write nested interfaces by hand — and with far less chance of a typo in a field name.

If your data also needs to travel between formats, the same structural thinking applies when you convert JSON to YAML for config files, or when you compare two payloads with a structured diff. Our guide to JSON diffing covers how the same tree-walking model powers comparison as well as code generation.

The takeaway

Generating TypeScript from JSON is a recursive mapping: primitives map directly, objects become named interfaces, and arrays become element-typed arrays with objects merged so optional keys are detected. The one thing inference can’t do is read your mind about optionality and nullability — so feed it a representative sample and refine the result. Done that way, JSON to TypeScript turns one of the more tedious parts of typed development into a paste-and-go step.

Advertisement

Try JSON to TypeScript — Free

Apply what you just learned with our free tool. No sign-up required.

Try JSON to TypeScript

Frequently Asked Questions

Can you generate types from a single JSON sample?
Yes, and it's the normal approach. A representative sample is enough to infer field names and types. The one limitation is optionality: a field that can be absent or null won't be detected unless your sample includes that case, so use a sample that covers the variations you expect.
Should I use interface or type for generated code?
Both work for object shapes. Interfaces support declaration merging and are conventional for object models; type aliases are more flexible for unions and intersections. For generated data models either is fine — pick what matches your codebase.
How are arrays of objects typed?
Objects in the same array are merged into one interface. A key present in every element is required; a key missing from any element becomes optional. This produces a single element type that accurately covers every object in the array.

Was this guide helpful?

Your feedback helps us improve our content.

Continue Reading

All Data Tools Guides

Get the best Data Tools tips & guides in your inbox

Join 25,000+ users who get our weekly data tools insights.