JSON to TypeScript Interface Generator

JSON Input
1
Root Name
TypeScript Output

Last updated:

Jsonic's JSON to TypeScript converter generates TypeScript interfaces from any JSON object. It infers types for strings, numbers, booleans, arrays, and nested objects. Nullable fields (null values) are typed as string | null. Arrays of mixed types produce union types. Deeply nested objects generate separate named interfaces. Paste your JSON and click Generate — no server involved.

How a JSON object maps to a TypeScript interface

Every key in a JSON object becomes one property in the interface, and each value picks the property's type: a JSON string becomes string, a number becomes number, and true/false become boolean. The generator walks the keys once, so a flat object converts in a single pass.

{
  "id": 42,
  "username": "alice",
  "active": true
}
interface Root {
  id: number;
  username: string;
  active: boolean;
}

Required, optional, and nullable fields

From a single JSON sample the generator cannot know which keys are optional — it only sees what is present, so every key is emitted as required. A value that is present butnull is a different case: it becomes a union with null, defaulting tostring | null because the real type is unknowable from null alone. Add the ? modifier yourself for keys the API may omit entirely.

{
  "userId": 1,
  "deletedAt": null
}
interface Root {
  userId: number;
  deletedAt: string | null;  // present but null -> union with null
  bio?: string;              // you add ? by hand: key may be absent
}

Nested objects become nested interfaces

A nested object is given its own named interface that the parent references by name, instead of being inlined or typed as any. This keeps the output readable and lets you reuse a shape like Address elsewhere. The generator recurses to any depth, emitting one interface per distinct object shape.

{
  "user": { "id": 1, "name": "Alice" },
  "address": { "city": "Springfield", "zip": "62701" }
}
interface Root {
  user: User;
  address: Address;
}

interface User {
  id: number;
  name: string;
}

interface Address {
  city: string;
  zip: string;
}

Array type inference and union types

Arrays of one primitive type become typed arrays (string[], number[]). An array of objects becomes an array of a named interface, with fields merged across every item so a key missing from some items is marked optional. Mixed-type arrays produce a union array rather than a lazy any[].

{
  "tags": ["dev", "premium"],
  "scores": [98, 87],
  "mixed": [1, "two", true],
  "items": [
    { "id": 1, "name": "Widget A" },
    { "id": 2, "name": "Widget B", "onSale": true }
  ]
}
interface Root {
  tags: string[];
  scores: number[];
  mixed: (number | string | boolean)[];
  items: Item[];
}

interface Item {
  id: number;
  name: string;
  onSale?: boolean;  // present on only some items -> optional
}

Generator vs. hand-written: quicktype and json-to-ts

Reach for a generator — this browser tool, quicktype, or the json-to-tsnpm package — whenever a payload is large, deeply nested, or changes often. quicktypegoes further than a single-sample tool: it infers nullable vs. optional from multipleJSON samples and can emit runtime validators next to the types.

# quicktype CLI — multiple samples sharpen nullable/optional inference
npm install -g quicktype
quicktype --lang typescript --out User.ts user1.json user2.json
// json-to-ts — programmatic, no runtime code
import jsonToTs from 'json-to-ts'
jsonToTs({ id: 1, name: 'Alice' }).forEach(i => console.log(i))

Write interfaces by hand only for small, stable shapes, or when you want precise literal unions a generator cannot infer — for example role: "admin" | "user" instead ofrole: string. For a deeper walkthrough see the JSON to TypeScript guide.

type vs interface, and runtime validation

Use interface for plain object shapes from JSON — it is the conventional default and can be extended. Switch to type when you need a union, tuple, or mapped type that an interface cannot express. Either way, remember that interfaces are erased at compile time and validate nothing at runtime; JSON.parse returns any and skips every check. Pair the generated interface with a validator to guarantee the shape.

import { z } from 'zod'

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  deletedAt: z.string().nullable(),
})

type User = z.infer<typeof UserSchema>          // same as the interface
const user = UserSchema.parse(JSON.parse(raw))  // throws on a bad shape

To go straight to a schema instead of an interface, try JSON to Zod. For typed Python models from the same JSON, see JSON to Pydantic.

How to convert JSON to TypeScript

  1. Paste your JSON object into the left panel.
  2. Click Generate to produce TypeScript interfaces.
  3. The root interface is named Root by default.
  4. Nested objects become separate named interfaces.
  5. Copy or download the result.

FAQ

How are nullable fields handled?

Fields with a null value are typed as string | null (or the inferred type | null). If you want stricter types, edit the JSON sample to include a non-null example.

How are arrays typed?

Arrays of primitives become typed arrays (e.g. string[]). Arrays of objects become interface arrays (e.g. Item[]). Mixed-type arrays become union arrays (e.g. (string | number)[]).

Can I rename the root interface?

Not yet — the root is always named Root. Rename it manually in the output after copying.

Does this send my JSON to a server?

No. The TypeScript generation runs entirely in your browser.

How are deeply nested objects handled?

Each nested object level generates its own named interface. For example, a "address" object inside "user" produces an Address interface that is referenced in the User interface.

What if my JSON has inconsistent array item types?

If array items have different shapes, the generator produces a union type covering all observed shapes.

Can I use this output directly in a TypeScript project?

Yes. Copy the output and paste it into a .ts or .d.ts file. You may want to rename Root to a more descriptive name.