# JSON to TypeScript

> Turn a JSON sample into TypeScript interfaces or a Zod schema, with a root name you choose. A starter to review, not a final schema. Free, in your browser.

Canonical: https://toolspace.tech/json-to-typescript/
Last updated: 2026-10-25

Paste a JSON sample and get TypeScript interfaces, type aliases or a Zod schema to start from. Nested objects get their own named types. It all runs in your browser.

This is an interactive tool that runs in the browser: [open the JSON to TypeScript](https://toolspace.tech/json-to-typescript/) to use it. Nothing typed into it is uploaded.

## Worked example

The second team member has an email and no lead flag, so both keys become optional. The empty tags array can’t say what it holds, so it stays unknown[].

**json**

```
{
  "id": 7,
  "name": "Ada",
  "manager": null,
  "tags": [],
  "team": [
    { "id": 1, "lead": true },
    { "id": 2, "email": "kofi@example.com" }
  ]
}
```

**typescript**

```
export interface Root {
  id: number;
  name: string;
  manager: null;
  tags: unknown[];
  team: TeamItem[];
}

export interface TeamItem {
  id: number;
  lead?: boolean;
  email?: string;
}
```

manager is typed null because null is all the sample shows. If it can also hold a person, change it by hand, for example to Person | null.

## Common mistakes

### Trusting one sample

One response can’t show every case. A field that happens to be present may be optional, and a string may only ever hold a few values. Read the types before you rely on them.

### Leaving null as null

A field that was null in the sample is typed null, which rejects every real value. Replace it with the type it holds when it’s set, plus | null.

### Leaving unknown\[\] in place

An empty array gives no clue about its items. Paste a sample where it has at least one item, or write the item type yourself.

### Using the types as validation

TypeScript types disappear at runtime, so they can’t check data from an API. Use the Zod output, or another runtime check, for data you don’t control.

## How it works

1. **Paste a JSON sample:** An API response, a config file or a fixture. Open a .json file or drop it on the left; it’s read on your machine and never uploaded.
2. **Pick the output:** Interfaces, type aliases or a Zod schema, with the root name you choose. Turn export and readonly on or off. Nested objects become their own named types, named after their key.
3. **Review, then copy or download:** Check the result against what your data can really hold, then copy it or save it as a .ts file.

## Questions

### How does it decide a field is optional?

Only from arrays. When an array holds several objects, their keys are merged: a key that appears in some elements but not others is marked optional (?: in TypeScript, .optional() in Zod). A single object can’t show that, so every key in it is required.

### What happens to null, empty arrays and mixed arrays?

A value that is only ever null is typed null. Null next to other values makes a union such as string | null (or .nullable() in Zod). An empty array is unknown[], because the sample says nothing about its items, and an array of mixed values becomes a union like (string | number)[].

### Why are some keys in quotes?

Keys that aren’t valid JavaScript identifiers, like "first-name", "2fa" or "a b", have to be quoted in a TypeScript type or a Zod object. Keys made of letters in any script, digits (not first), $ and _ stay bare.

### Does the Zod schema need a particular version?

It uses z.object, z.array, z.union, z.record, z.unknown, .nullable() and .optional(), which exist in both Zod 3 and Zod 4. Schemas for nested objects are declared before the ones that use them.

### Is my JSON uploaded?

No. The types are worked out in this tab, and nothing is sent anywhere.

## Related

- [JSON formatter](https://toolspace.tech/json-formatter/)
- [JSON validator](https://toolspace.tech/json-validator/)
- [JSON to YAML](https://toolspace.tech/json-to-yaml/)
- [Mock data generator](https://toolspace.tech/mock-data-generator/)
