Free tool

JSON to TypeScript converter

Paste JSON and get TypeScript interfaces or type aliases, or a Zod schema, as you type. Every array item is merged, so keys that only some items have become optional and mixed values become unions.

Free · no sign-up · runs in your browser, nothing is uploaded

JSON input
412 B
Drop a .json or .jsonl file here, or click to open one
TypeScript3 declarations
export interface Root {
  id: number;
  login: string;
  email: string;
  createdAt: string;
  isAdmin: boolean;
  score: number;
  website: null; // null in every sample
  tags: string[];
  address: Address;
  repos: Repo[];
}

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

export interface Repo {
  name: string;
  stars: number;
  private: boolean;
  topics?: string[];
  license?: string;
}

How the types are inferred

The converter walks the whole document, not just the first array item. Each spot in the data collects every value it saw, and the type is built from all of them. That is why a sample with 20 users gives a better type than a sample with one.

In the JSONIn TypeScriptWhy
"name": "Ada"name: stringStrings, numbers and booleans map directly.
"zip": null in one item, a string in anotherzip: string | nullPresent but sometimes null.
"license" in only some array itemslicense?: stringMissing from some items, so optional.
[1, "two"](string | number)[]Mixed array items become a union.
"address": { ... }address: AddressEach nested object gets a named type.
"repos": [{ ... }]repos: Repo[]Array item types are named in the singular.
"tags": []tags: unknown[]Nothing to infer from; the output says so in a comment.
"meta": {}meta: Record<string, unknown>An object only ever seen empty is usually a map.
"first-name": "x""first-name": stringKeys that are not valid identifiers are quoted.

Two objects with exactly the same fields share one type, so home and work addresses both become Home instead of two copies. When two different shapes want the same name, the second gets a number (Item2); rename it in your editor. You can also paste JSON Lines (one object per line, as in logs and .ndjson exports) and every line is merged as one sample.

interface or type?

For JSON data the two produce the same checks. The TypeScript handbook lists the real differences: an interface can be reopened to add fields (declaration merging) and extended with extends; a type alias cannot be reopened, but it can name unions, tuples and primitives.

// interface: can be extended and merged
interface User { id: number; name: string }
interface Admin extends User { permissions: string[] }

// type alias: can name a union, cannot be reopened
type Id = number | string;
type User = { id: Id; name: string };

A root that is an array or a primitive is always a type alias (type Root = RootItem[]), because an interface can only describe an object.

Types vanish at runtime: use Zod to check real data

TypeScript types are removed when the code is compiled, so JSON.parse(body) as User checks nothing. If the API changes or returns an error object, the bug shows up later and far away. A schema library checks the data when it arrives. Pick Zod schema above to get the schemas and the types in one go:

import { z } from 'zod';

export const RepoSchema = z.object({
  name: z.string(),
  stars: z.int(),
  license: z.string().optional(),
});
export type Repo = z.infer<typeof RepoSchema>;

const repo = RepoSchema.parse(await res.json()); // throws if the shape is wrong

Zod 4 has top-level format checks such as z.email(), z.url() and z.iso.datetime(); the Zod 3 output uses the older z.string().email() forms, which Zod 4 still accepts but marks as deprecated. Format checks are only added when every sampled value matches, and z.uuid() is only used when the samples follow the RFC version and variant bits (Zod 4 checks them); otherwise you get z.guid().

Other ways to get types from JSON

Import the file. With "resolveJsonModule": true in tsconfig.json, import data from './data.json' gets a type inferred from the file. Good for config and fixtures you keep in the repo.

quicktype CLI. Generates types and runtime converters in many languages from JSON samples, JSON Schema or GraphQL:

npx quicktype users.json -o User.ts
npx quicktype users.json --lang go -o user.go

From a JSON Schema. If the API publishes a schema, generate types from it instead of from a sample, since the schema knows about fields your sample happens to lack. You can also build a schema from samples with the JSON Schema generator.

Gotchas

  • Your sample is all the tool knows. A field that is never null in the sample will not be typed as nullable. Paste several responses, including error and empty ones, to get honest types.
  • Dates are strings. JSON has no date type, so "2024-03-01T09:30:00Z" is a string. Convert it with new Date() after parsing, or use z.coerce.date() in Zod.
  • Big integers lose precision. JSON.parse turns numbers into doubles, which are exact only up to Number.MAX_SAFE_INTEGER (2^53 - 1). IDs like Twitter's are sent as strings for this reason; keep them as string.
  • Integers and decimals are both number. TypeScript has one number type. The Zod output uses z.int() (Zod 4) or .int() (Zod 3) when every sample is a whole number.

Need to tidy the JSON first? Use the JSON formatter. To pull one part out of a big response, try the JSONPath tester. For more developer APIs and SDKs, browse API tools on DevHunt.

FAQ

How do I convert JSON to a TypeScript interface?+

Paste the JSON into the box above. The interfaces appear on the right as you type, one per nested object, named after the key it sits under. Copy them or download types.ts. On the command line, quicktype data.json -o Types.ts does the same job.

Should I use interface or type for JSON data?+

Either works for plain object shapes, and the TypeScript handbook says you can mostly choose by taste. Interfaces can be extended and reopened (declaration merging); type aliases cannot be reopened but can name unions and other types. Many teams use interface for objects and type for everything else.

How do I import a JSON file in TypeScript?+

Turn on "resolveJsonModule": true in tsconfig.json, then write import data from "./data.json". TypeScript infers a type from the file contents. Use the generated interface when the data comes from an API rather than a file in your repo.

How are optional fields detected?+

Every object in an array is merged into one type. A key that is missing from some of the objects becomes optional (key?: type). A key that is present but sometimes null becomes type | null. You can also make every field optional or every field required with the switch above the editor.

Does TypeScript check JSON at runtime?+

No. Types are erased when TypeScript compiles to JavaScript, so JSON.parse(text) as User only tells the compiler to trust you. To check real data, validate it at runtime with a schema library. Switch the output to Zod to get a schema plus the matching type from z.infer.

How do I parse a JSON string into a typed object?+

JSON.parse returns any, so annotate the result: const user: User = JSON.parse(text). That compiles, but nothing checks the shape. For data from outside your code, prefer UserSchema.parse(JSON.parse(text)) with the Zod output, which throws if the data does not match.

Is my JSON sent to a server?+

No. The types are generated in your browser and nothing is uploaded. Short inputs are kept in the page URL so you can share a result, so do not share a link that contains private data.

Sources: TypeScript handbook: type aliases vs interfaces · tsconfig: resolveJsonModule · Zod 4 API · Zod 4 changelog · quicktype · MDN: JSON.parse() · MDN: Number.MAX_SAFE_INTEGER. Checked 2026-10-29.