[JSONZen]
Sign up and get Pro free for 3 months — no card required.Claim it →

Conversion guide

JSON to TypeScript: Generate Interfaces

Generate accurate TypeScript interfaces from a JSON sample. Handles nested objects, unions, optional fields, and nullable values without hand-typing.

Writing TypeScript interfaces by hand for a 200-field API response is grunt work that nobody wants to do. Generating them from a JSON sample is faster and more accurate — typos in field names are impossible, and the structure stays in sync with the real payload. This guide walks through how the conversion works, what the generator gets right, and where it needs help.

Paste a sample into the JSON to TypeScript generator for instant output, or read on for the structural rules and edge cases.

TL;DR

A JSON to TypeScript converter walks the value tree and emits a matching type for each node: objects become type Foo = { ... }, arrays become T[], primitives map directly. Names come from the JSON keys; shapes are widened across multiple samples to catch optional and nullable fields. The output compiles as-is with strict: true.

Step 1 — Primitives and flat objects

The simplest payload is a flat object of primitive values. Each JSON type maps to one TypeScript type.

Input

{
  "id": 1,
  "name": "Widget",
  "price": 19.99,
  "inStock": true,
  "discontinuedAt": null
}

Output

type Widget = {
  id: number;
  name: string;
  price: number;
  inStock: boolean;
  discontinuedAt: null;
};

JSON has one numeric type; TypeScript has number. JSON null becomes the literal type null rather than unknown — narrower types catch more bugs. If you know the field will sometimes be a real value, pair it with the multi-sample widening below.

Step 2 — Nested objects

Nested objects become nested types, each given a name derived from its key. Inline or named depends on tool config.

Input

{
  "id": "globex-cat-001",
  "vendor": {
    "name": "Globex",
    "country": "US"
  },
  "stock": {
    "warehouse": "WH-7",
    "qty": 240
  }
}

Output (inline)

type CatalogEntry = {
  id: string;
  vendor: {
    name: string;
    country: string;
  };
  stock: {
    warehouse: string;
    qty: number;
  };
};

Output (extracted)

type Vendor = {
  name: string;
  country: string;
};

type Stock = {
  warehouse: string;
  qty: number;
};

type CatalogEntry = {
  id: string;
  vendor: Vendor;
  stock: Stock;
};

Extract named types when the same shape appears in multiple places. Inline keeps the output readable for one-off responses.

Step 3 — Arrays

Arrays become element-type arrays. The generator inspects every element to widen the type.

Input

{
  "tags": ["new", "discounted", "featured"],
  "items": [
    { "sku": "widget", "qty": 2 },
    { "sku": "gadget", "qty": 5 }
  ]
}

Output

type Order = {
  tags: string[];
  items: { sku: string; qty: number }[];
};

Mixed-type arrays widen to unions. ["a", 1, true] becomes (string | number | boolean)[]. If that union surprises you, the source data probably needs cleaning before generation.

Step 4 — Optional and nullable fields

Feed multiple samples and the generator marks fields that are missing from at least one sample as optional, and fields that are sometimes null as nullable.

Input (two samples)

[
  { "id": "u_001", "email": "otter@example.com" },
  { "id": "u_002", "email": null, "verifiedAt": "2026-01-15" }
]

Output

type User = {
  id: string;
  email: string | null;
  verifiedAt?: string;
};

email was never absent but was sometimes nullstring | null. verifiedAt was absent in the first sample → optional. Single-sample inference can't catch either of these, so feed multiple samples whenever you have them.

Step 5 — Reuse the contract at runtime

TypeScript interfaces vanish at runtime. If the API ever drifts, your code happily reads garbage. Pair the generated type with a runtime validator:

Strict typing without runtime validation is faith-based programming when the JSON comes from a network call.

Common conversion problems

"Every field came out as any"

The generator probably saw an empty object or an empty array and could not infer further. Feed a sample with real values, not the placeholder skeleton from your docs.

"Numbers and booleans came out as string"

The JSON quoted them. "price": "19.99" is a string; the converter cannot guess your intent. Fix the source data or post-process the type by hand.

"The output names are ugly"

Keys like 2fa-enabled produce identifiers like '2fa-enabled' (which is valid TS but reads badly). Rename in the source if possible, or use the generator's "PascalCase keys" option.

"I have a recursive structure and the output exploded"

Self-referencing data — a tree node with a children array of the same shape — produces infinite nesting unless the generator detects the recursion. Most generators do; if yours doesn't, name the outer type and reference it manually for the recursive field.

"The type is right but my IDE shows any"

Check that the generated file is included in your tsconfig.json include glob. The compiler can't help with a file it's not parsing.

Generate in the browser, no upload

The free JSON to TypeScript generator on JSONZen runs entirely client-side. It handles nested objects, unions across multiple samples, and optional fields, and emits compilable code that respects your TypeScript strict-mode settings.

For a complete API-contract workflow, generate a Zod schema too and use Zod's z.infer to derive the TypeScript type from the validator — keeping compile-time and runtime types in lockstep.

Closing recommendation

Generate the interface, paste it in, then add a Zod schema where the JSON crosses a network boundary. That gives you precise types at compile time and a clear failure at runtime when the API changes shape — the only combination that survives real-world API drift.

Related guides

Related tools