JSON to TypeScript

Turn a JSON response into TypeScript interfaces. Every nested object gets its own named interface, and a key that is missing from some elements of an array comes out optional instead of required.

JSON Input
Generated Code

1 JSON to TypeScript example

JSON sample

1
2
3
4
5
6
7
{
  "id": 1,
  "name": "Ana",
  "orders": [
    { "order_id": 1001, "note": "gift" },
    { "order_id": 1002 }
  ]
}

Generated

1
2
3
4
5
6
7
8
9
10
export interface Order {
    order_id: number;
    note?: string;
}

export interface User {
    id: number;
    name: string;
    orders: Order[];
}

2 What it infers, and what it cannot

Optional keys

Arrays are scanned in full, not sampled. A key present in some elements and absent from others becomes optional, which usually matches an API that leaves out null fields.

Merged number types

JSON has one number type. A field that is 10 in one record and 12.5 in another comes out as number, since TypeScript has no separate integer type either.

Named nested types

A nested object becomes its own exported interface instead of an inline shape three levels deep, so you can import it elsewhere and use it in a function signature.

Nulls it has never seen

A field that is null in every sample has nothing to infer from and comes out as null. Use a sample with a real value there, or write that one type by hand.

3 A type is not a validator

An interface checks nothing at runtime. TypeScript erases it at compile time, so if the API changes shape, the code still compiles and then throws three functions away from the cause.

The fix is to validate at the boundary and derive the type from the validator, not the other way round. With zod you write the schema once and get the type from z.infer; with a JSON Schema you can generate both. Use this page to see the shape quickly, then decide whether the data crossing that boundary needs a runtime check.

How to use the JSON to TypeScript tool

  1. Paste a JSON sample into the left panel, or load a file with Upload File.
  2. Set Root name to whatever the top-level type should be called. JSON has no name for it, so the tool cannot guess.
  3. Tick Use type alias if your codebase prefers type over interface.
  4. The interfaces appear on the right as you type. Copy Result or Download saves them as types.ts.

How to get types from JSON in a real project

TypeScript: derive the type from a validator

// npm i zod
import { z } from "zod";

const Order = z.object({
    order_id: z.number(),
    total: z.number(),
    note: z.string().optional(),
});

const User = z.object({
    id: z.number(),
    name: z.string(),
    orders: z.array(Order),
});

// One source of truth: the schema checks at runtime, the type comes from it
type User = z.infer<typeof User>;

const res = await fetch("/api/user/1");
const user = User.parse(await res.json()); // throws if the API changed shape

We recommend this pattern. A generated interface tells the compiler what you expect to arrive; a schema checks what arrived.

Generating types in a build step

# From a JSON sample
npx quicktype --lang ts --src-lang json sample.json -o types.ts

# From a JSON Schema, which carries more information
npx json-schema-to-typescript schema.json -o types.d.ts

# From an OpenAPI spec, if the API publishes one
npx openapi-typescript https://api.example.com/openapi.json -o api.d.ts

# The last one is the best option when it is available: the types stay
# in step with the API because they are generated from its own contract.

Common errors and how to fix them

A field came out as null
Every sample had null there, so there is nothing to infer. Supply a sample that includes a real value, or edit the type by hand to string | null.
Property 'x' does not exist on type
The sample did not contain that key. If the key is optional, add it as x?: T; if the sample was incomplete, regenerate from a fuller response.
The API changed and nothing broke until production
This is expected: interfaces are erased at compile time and check nothing at runtime. Validate at the boundary with zod, valibot or a JSON Schema check.
Numbers that should be integers are typed as number
TypeScript has no integer type, so number is the correct and only answer. If the distinction matters, enforce it in the validator instead.

Good to know

Interfaces and type aliases are close to interchangeable for a shape derived from JSON. Interfaces can be reopened and merged across declarations, which matters when you are augmenting a library's types; type aliases can express unions and mapped types, which interfaces cannot. For plain data, use whichever your codebase already uses.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

How are nested objects handled?

Each one becomes its own named interface instead of an inline type. A declaration nested three levels deep is valid but hard to read, and a named interface is something you can export and reuse.

What happens to arrays of objects?

The tool looks at every element, not just the first, and merges the keys it finds. A field missing from some elements comes out optional, which usually matches an API that leaves out null fields.

Why did a field come out as any?

It comes out as unknown rather than any, for two reasons. An empty array in every sample gives unknown[], and elements that disagree on the type, such as a string in one and a number in another, give unknown. A field that is null in every sample comes out as null. Widen the sample or write that type by hand.

Should I use interface or type?

Either works. Interfaces can be extended and merged across declarations, and type aliases can express unions. For a shape derived from JSON the difference rarely matters, so the tool emits interfaces, and Use type alias switches the output if your codebase prefers aliases.

Is this a substitute for validating the response?

No. A TypeScript interface is erased at compile time and asserts nothing at runtime, so if the API changes shape, the code still compiles and then throws. Validate at the boundary with zod, io-ts or a JSON Schema check, and derive the type from that.

Related

The same sample produces a Go struct, a Python dataclass or a JSON Schema, and the schema is the one you can validate data against. To tidy the sample first, use the JSON formatter.

More Data Converters

Browse all data converters

Copied to clipboard!