JSON to TypeScript

Paste or upload a JSON sample to generate TypeScript types. Runs in your browser.

Pasted text and chosen files stay on this device. Nothing is sent to a server.

Drop a file here, choose one, or paste.

No output yet Generate to see the result here.

How to use it

  1. 1

    Paste one response.

  2. 2

    Read the optional count, then decide which of those fields to make required — that is a decision about your API, not about the sample.

What it does

The type system is the thing being written to, so the hard parts are the ones TypeScript makes hard: a field observed once is not a field that is always there, an array holding a number and a string is a union rather than one type, and an object whose keys vary needs an index signature rather than a property list.

Walk the sample and emit interfaces. Report, per field: whether it is emitted optional, whether its type is a union, and whether an index signature was needed. Never emit `any` silently.

Why it works this way

A field present in the sample is not a field always present, so fields observed once are emitted with `?`. That is TypeScript's own way of saying it, which is why this decision belongs on this page rather than on the schema page.

An array holding a number and a string becomes `(number | string)[]`, not `any[]`. A union is what the sample actually showed, and it keeps the compiler checking the members.

When a nested object has a varying key set the generator emits an index signature and says so. `unknown` is the value type it prefers, because `any` switches checking off for every member rather than for the one that is uncertain.

null is a member of the type, not an absence. `string | null` and `string?` are different claims and the sample decides which one it supports.

Examples

{"a": 1, "b": null}
interface Root {
  a: number;
  b: null;
}
null is a type of its own here; `b?` would claim it can be absent, which the sample does not show
{"a": [1, "x"]}
interface Root {
  a: (number | string)[];
}
a union, not any[] — the sample showed exactly two member types
{"a": {"k1": 1, "k2": 2}}
interface Root {
  a: { [key: string]: number };
}
two keys that look like a pattern get an index signature rather than two fixed properties

Inputs and outputs

  • JSON sample
  • root type name
  • optional marking: observed once / never / always
  • index signatures: on / off
  • TypeScript source
  • counts: fields marked optional, unions emitted, index signatures added

Edge cases

  • an array of mixed types — union
  • an empty array — the element type is unknowable, reported rather than guessed
  • a key that is not a valid identifier — quoted
  • null alongside a type
  • an object whose keys are all distinct and non-patterned — no index signature
  • a field whose only value was a number in one object and a string in another

Frequently asked questions

Why is my field optional?

It was observed once. One observation cannot show a field is always present, so it is emitted with `?` and you can make it required deliberately.

Why an index signature instead of my keys?

The sample's keys looked like a pattern rather than a fixed set. Fixed properties would reject a response with one more key.

Why unknown and not any?

`any` turns checking off for everything that touches it. `unknown` keeps the check on and makes you narrow the type first.

Related tools

Sources

  • TypeScript handbook: Everyday Types, Object Types, Index Signatures