JSON to TypeScript: Generate Types and Interfaces
Turn JSON samples into TypeScript interfaces. Learn how type inference works, interface vs type alias, optional and nullable fields, arrays and unions, and how to refine generated types for production.
Hand-writing TypeScript interfaces for a large API response is tedious and error-prone. Generating them from a real JSON sample is faster and more accurate — you get compile-time safety and editor autocomplete over data that was previously untyped. This guide explains how JSON-to-TypeScript generation works, the choices it makes about optional and nullable fields, and how to turn a good first draft into production-ready types.
Why generate types from JSON?
TypeScript only protects you if your data is typed. An API response typed as any silently defeats the compiler. Generating an interface from a representative JSON sample gives you autocomplete, refactoring safety, and red squiggles when you access a field that does not exist — all derived from the actual shape of the data rather than a guess.
How type inference works
A generator walks the JSON and maps each value to a TypeScript type: strings to string, numbers to number, booleans to boolean, and objects to their own named interface. Arrays become typed arrays, so a list of numbers becomes number[] and a list of objects becomes an interface array. Each nested object produces its own interface, yielding a complete, readable type graph instead of one giant inline shape.
{ "id": 1, "name": "Ada", "tags": ["x"], "active": true }interface User {
id: number;
name: string;
tags: string[];
active: boolean;
}Interface versus type alias
TypeScript can express object shapes as either an interface or a type alias. Interfaces are conventional for object shapes, support declaration merging, and produce clean extends hierarchies — a good default for generated models. Type aliases shine for unions and primitives. For JSON-derived object models, interfaces are usually the clearer choice, but either works and the two are largely interchangeable for plain data.
Optional and nullable fields
This is where a single sample falls short. If a field is absent in your example, the generator cannot know it exists; if it is present but sometimes null in reality, the generated type will not reflect that. After generating, mark fields that may be missing as optional (name?: string) and fields that may be null as a union (name: string | null). Feeding the generator a sample that includes the nullable and optional cases produces better output up front.
interface User {
id: number;
nickname?: string; // may be absent
deletedAt: string | null; // may be null
}Arrays, unions, and mixed types
Arrays of mixed types become a union element type, such as (string | number)[]. When the same field holds different types across records — a number here, a string there — you will want a union like string | number rather than the type from a single example. Empty arrays are ambiguous because there is nothing to infer from, so they often default to any[] or unknown[] and deserve a manual pass.
Refining generated types for production
- Add optional markers (?) to fields that can be absent
- Widen single-sample types to unions where a field varies (string | null, number | string)
- Replace string with literal unions for known enums, such as 'active' | 'archived'
- Rename auto-generated nested interface names to something meaningful
- Treat the output as an accurate first draft you review, not a finished contract
From sample to schema
Types generated from one example describe that example. When you need a runtime contract that validates incoming data — not just compile-time types — generate a JSON Schema from the same sample and validate against it with a library like Zod or Ajv. Use the JSON to TypeScript tool to scaffold your interfaces and the JSON Schema Generator when you also need runtime validation, keeping a single source of truth for the shape.
Frequently asked questions
How do I convert JSON to a TypeScript interface?
Paste a representative JSON sample into a JSON-to-TypeScript generator. It infers a type for each value and emits named interfaces for nested objects, giving you a complete typed model you can drop into your code.
Should I use interface or type for JSON models?
Interfaces are the conventional, readable choice for object shapes derived from JSON and support extends and declaration merging. Type aliases are better for unions and primitives. For plain data models the two are largely interchangeable.
Why are some generated fields wrong or too narrow?
Types are inferred from a single sample, so a field that is null or absent in reality but present in your example will be mistyped. Review the output and add optional markers and union types where the data actually varies.
How do I handle fields that can be null?
Mark them as a union with null, for example name: string | null. A generator cannot infer nullability from a non-null sample, so this is a manual refinement — or include a null case in the sample you feed it.
Do generated types validate data at runtime?
No. TypeScript types are erased at compile time and do not check incoming data. For runtime validation, generate a JSON Schema and validate with a library like Zod or Ajv alongside your generated types.
Related tools
Try these tools
JSON to TypeScript Types
Generate TypeScript interfaces and types from any JSON sample.
JSON Schema Generator
Infer a JSON Schema from example data in one click.
JSON Validator
Validate JSON instantly with precise, human-readable error messages and line numbers.
JSON Formatter & Beautifier
Format, prettify, and beautify messy JSON with configurable indentation and key sorting.