Developer tools

JSON to TypeScript and JSON Schema

Turn sample JSON into TypeScript interfaces and a draft 2020-12 JSON Schema, with optional keys and unions inferred from the samples.

JSON to TypeScript and JSON Schema
Esc to restore

Your inputs

One JSON document, or one sample per line (JSON Lines). Up to 2 MB.

Results update as you type. Larger files run when you press Update result.

Your result

Your result will appear here.

More actions

Your inputs stay in this browser. Nothing is uploaded or saved.

A clear answer. Here’s how.

Walks every sample and records, for each place in the document, which JSON kinds occur there (object, array, string, number, boolean, null) and, for objects, each key and how many samples had it. A key present in every sample is required; one missing from some is optional (key?: in TypeScript, left out of required in the schema). Different kinds at one place become a union (string | null; a type list or anyOf in the schema), array elements are merged into one element type, and an empty array gives unknown[]. Names are deterministic: PascalCase from the key, a singular form for array elements (orders gives Order, entries Entry, people Person), and a numeric suffix when a name is taken. The TypeScript uses interfaces or type aliases, optionally readonly; the schema follows JSON Schema draft 2020-12 (type, properties, required, items) with integer when every number is whole, and format date-time (RFC 3339), email or uri only when every string at that place matches and the option is on. Dates stay string in TypeScript. Inference only sees the samples given: it cannot know about keys, values or constraints they do not show, and it does not generate enums, tuples, additionalProperties or $defs.

How this is checked

5 reference checks passed These 5 cases were run when this page was built, on 20 October 2026, and all reproduce within the stated tolerance. The same cases are part of the automated tests that run on every change to Toolmoz. Engine version 1.

See the checks and where each expected answer comes from
  1. Case 1

    Inputs
    Sample JSON {"id":1,"name":"Ann"}
    Expected, and what Toolmoz gave
    text expected export interface Root { id: number; name: string; } , Toolmoz export interface Root { id: number; name: string; } Types declared expected 1, Toolmoz 1
    Where the expected answer comes from
    Hand derivation: one object with two keys present in the only sample, so both are required; 1 is a number and "Ann" a string
    Allowed difference
    exact
  2. Case 2

    Inputs
    Sample JSON {"id":1,"tag":"a"} {"id":2}The input is lines
    Expected, and what Toolmoz gave
    text expected export interface Root { id: number; tag?: string; } , Toolmoz export interface Root { id: number; tag?: string; } Optional properties expected 1, Toolmoz 1
    Where the expected answer comes from
    Hand derivation: id appears in 2 of 2 samples (required); tag in 1 of 2 (optional, tag?)
    Allowed difference
    exact
  3. Case 3

    Inputs
    Sample JSON {"items":[{"sku":"A","qty":1},{"sku":"B","qty":2.5,"note":null}]}
    Expected, and what Toolmoz gave
    text expected export interface Root { items: Item[]; } export interface Item { sku: string; qty: number; note?: null; } , Toolmoz export interface Root { items: Item[]; } export interface Item { sku: string; qty: number; note?: null; } Types declared expected 2, Toolmoz 2
    Where the expected answer comes from
    Hand derivation: items holds 2 objects, merged into one element type named Item (singular of items); sku and qty in 2 of 2, note in 1 of 2 and only ever null
    Allowed difference
    exact
  4. Case 4

    Inputs
    Sample JSON [1,"a",null]
    Expected, and what Toolmoz gave
    text expected export type Root = (string | number | null)[]; , Toolmoz export type Root = (string | number | null)[]; Unions expected 1, Toolmoz 1
    Where the expected answer comes from
    Hand derivation: the root is an array whose elements are a number, a string and null, so the element type is one union, string | number | null
    Allowed difference
    exact
  5. Case 5

    Inputs
    Sample JSON {"when":"2026-10-18T09:30:00Z","n":3}Show schema
    Expected, and what Toolmoz gave
    text expected { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Root", "type": "object", "properties": { "when": { "type": "string", "format": "date-time" }, "n": { "type": "integer" } }, "required": [ "when", "n" ] } , Toolmoz { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Root", "type": "object", "properties": { "when": { "type": "string", "format": "date-time" }, "n": { "type": "integer" } }, "required": [ "when", "n" ] }
    Where the expected answer comes from
    Hand derivation: when is an RFC 3339 date-time string in every sample, n is a whole number (integer), and both keys are present, so both are required
    Allowed difference
    exact

What this shows: the engine reproduces independently worked values for these cases. It does not prove every possible input is right. To test an answer you were given, see how to check a number; to see what is and is not checked across Toolmoz, see the accuracy ledger.

See a worked example

Worked example

A fixed demonstration, separate from the values you enter above.

Sample JSON
{
  "id": 42,
  "name": "Ann",
  "email": "ann@example.com",
  "joined": "2026-10-18T09:30:00Z",
  "tags": ["admin", "editor"],
  "address": { "city": "Leeds", "postcode": null },
  "orders": [
    { "sku": "A-1", "qty": 2 },
    { "sku": "B-7", "qty": 1, "note": "gift" }
  ]
}
The input is
One JSON document
Name of the root type
Root
TypeScript declarations
export interface
Readonly properties and arrays
No
String formats in the schema
Add date-time, email or uri when every sample matches
Show
TypeScript

Example result

Samples
1
Values read
19
Types declared
3
Optional properties
1
Unions
0

Inferred from 1 sample only: a key missing from some samples becomes optional (?), different kinds of value at the same place become a union, and an empty array becomes unknown[]. Numbers are number in TypeScript and integer in the schema when every sample is a whole number. Dates stay as string. The schema lists required keys and types; it does not forbid extra properties. Check the result against more data before relying on it.