EN

JSON to TypeScript

Generate TypeScript interfaces from JSON

FAQ

Are nested objects turned into separate interfaces?

Optional. Expand mode generates an interface per nested object; inline mode keeps them inside the parent.

How are array types written?

Both T[] and Array<T> styles are supported, pick whichever your project uses.

How is the optional marker decided?

A field is marked optional when it is missing from some elements of an array. Inconsistent samples therefore produce looser types.

About this tool

Turns a JSON sample into TypeScript type definitions. Two switches decide the shape: nested objects either expand into separate interfaces or stay inline as { a: string }, and arrays can render as T[] or Array<T>. The root interface name is editable.

Three things that actually break generated code, all handled here:

  • Keys that are not valid identifiers need quotes. {"user-name": 1} must produce "user-name": number;; emitting user-name: number; is a syntax error, which is exactly what many online converters do.
  • Optional fields come from array membership. [{"id":1,"name":"a"},{"id":2}] yields name?: string; because the second element has no name. That is a detectable rule rather than a guess: a key present in every element is required, one missing anywhere is optional.
  • Same-named objects with different shapes are not merged. When data.address and meta.address differ, you get Address and Address2 instead of the second one being silently dropped.

Other behaviour: array element types are unioned, so [1,"a"] becomes (number | string)[]; an empty array is unknown[]; a null value types as null (and unions with siblings as string | null); an array root emits type Root = Item[] plus interface Item.

What it does not do: it does not infer literal unions such as "new" | "done" (that needs samples covering every value), it does not generate runtime validation (use zod or io-ts for that), it does not merge structurally similar objects, and every number becomes number - so JSON containing integers above 2^53 (an 18-digit order id, say) loses precision and should be typed as string by hand.

One distinction worth keeping: name?: string means the key may be absent, while name: string | null means it is always present but may be null. A JSON null is the latter, which is why this tool emits | null.