JSON → types
Paste JSON samples (or a JSON Schema) and get TypeScript, Zod, Java records with Jackson (or Lombok classes), Kotlin, Go structs, Rust serde, Python pydantic or dataclasses, protobuf, or JSON Schema — merging samples to find optional fields, nulls, unions, enums, dates, UUIDs, maps and tagged unions.
Added
Works with
- JSON workbench DataMake types in the JSON workbench sends its document here, and Open in JSON workbench takes the input back
- Data converter DataMore type options… in the data converter sends its input here as JSON
How to use it
Paste a response from an API, a log line or a config file and get the types to read it with. The
more samples you give, the better the types: a key missing from one sample becomes optional, a
null makes a field nullable, a number in one sample and a string in another makes a union. It
also takes a JSON Schema and writes the same types from that.
The data converter has a quick JSON → TypeScript / Go / Rust / Python of a single document; this tool is the thorough version. To run the TypeScript it writes, use the TypeScript playground.
How to use it
Paste on the left, or Open file…. The input can be one document, an array of records, JSON
Lines (one document per line, as in logs and kubectl … -o json streams), several documents one
after another, or a JSON Schema (draft-07 to 2020-12, and OpenAPI’s nullable). Auto decides
which; Samples / JSON Schema force it. The Examples… show each feature.
What it works out, listed under What it found:
-
Optional fields — present in some objects at a position but not all — and nullable ones —
nullin at least one sample. Every sample counts, including every element of every array. -
Unions when a field has several kinds (a number in one place, a string in another).
-
String formats: RFC 3339 date-times (with a zone, so Go’s
time.Timeand Java’sOffsetDateTimecan parse them), dates, times, UUIDs, emails, URLs, IPv4 addresses. -
Enums: a string field with a few values (up to 8, configurable) that repeat and look like identifiers —
"active","disabled"— not names or free text. -
Maps: an object whose keys are data (numeric ids, UUIDs, dates) becomes a map, and
{}a free-form object, rather than a type per key. -
Tagged unions: objects with a string
type,kind,event,op… where the other fields depend on it become a discriminated union — TypeScript|with literal tags,z.discriminatedUnion, a Jackson@JsonTypeInfosealed interface, a kotlinx sealed interface, a serde#[serde(tag = "type")]enum, a pydanticField(discriminator=…)union. Go and protobuf have no sum types, so there it is one struct with every variant’s fields and the tag. -
Names: nested types are named after their keys (
address→Address; array items are made singular:categories→Category); identical shapes share one type; a different shape with a taken name gets the parent’s name in front (OwnerAddress). Set the root name and a prefix or suffix (Dto).
JavaScript reads 1.0 as 1, so a float field whose samples are all whole numbers looks like an
integer; tick Numbers as floats, or include a sample with a fraction.
Each language follows its own conventions, with the JSON names kept where they differ:
-
TypeScript — interfaces or type aliases,
key?orkey?: T | undefined(forexactOptionalPropertyTypes), string-union orenumenums,readonly. -
Zod — schemas plus
z.infertypes; recursive schemas getz.lazyand written-out types. Works with Zod 3 and 4. -
Java — records (Java 17+) or Lombok
@Data @Builderclasses, with Jackson annotations;OffsetDateTime,LocalDateandUUIDfor formats (or plain strings); boxed types for nullable and optional fields; one file per type. -
Kotlin —
@Serializabledata classes for kotlinx.serialization,@SerialNamewhere names differ, nullable types with= nulldefaults. -
Go — structs with
json:"…"tags,omitemptyon optional fields, pointers for nullable ones (or for optional too, or never), Go initialisms (ID,URL,UUID),time.Time, string enums with constants, and `gofmt’s alignment. -
Rust — serde structs,
[serde(rename_all = "camelCase")]when one rule fits every field (else per-fieldrename),Option<T>withskip_serializing_if,[serde(untagged)]enums for unions,Boxfor recursion, raw identifiers for keywords (r#type). -
Python — pydantic v2 models with
Field(alias=…)(snake_case attributes, JSON names kept), or dataclasses with required fields first. -
Protobuf — proto3 messages with
optional,repeated,map<…>,json_namewhere the JSON name is not the proto default, andgoogle.protobuf.Value/ListValuefor what proto cannot say directly (unions, arrays of arrays). -
JSON Schema — draft 2020-12 with
$defs,required, formats andoneOffor tagged unions.
Copy or Download the result. Share link puts the input and settings in the URL.
Checked with the real compilers
While building this I generated every language for five test inputs (an array of users, JSON
Lines events with a type tag, awkward keys and mixed values, a GitHub-style API response, and a
JSON Schema with $ref, recursion and a oneOf) and checked the output with the real tools:
TypeScript 6 tsc --strict --exactOptionalPropertyTypes with each sample assigned to the type;
Zod 3 and 4 parsing each sample; javac with Jackson reading each sample into the records and the
Lombok classes; gofmt, go vet and encoding/json decoding each sample with unknown fields
disallowed; cargo with serde decoding each sample; pydantic validating each sample; protoc;
and ajv validating each sample against the generated schema. Kotlin was not compiled.
Working with other tools
The JSON workbench has a Make types button that sends its document here; Open in JSON workbench here sends the input (or, on the JSON Schema tab, the generated schema) back there to format, query or diff. In the data converter, when the output is a type language, More type options… converts the input (YAML, CSV, XML, TOML…) to JSON and opens it here.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.