JSON to TypeScript, Pydantic & Go

Paste a JSON sample and get TypeScript interfaces, Pydantic v2 models, Go structs or a JSON Schema. An array of objects folds into one type, with optional and nullable fields worked out from the rows.

Target

Same thing, as an API

curl -X POST 'https://akifakkaya.com/api/v1/tools/json/types' \
  -H 'Content-Type: application/json' \
  -d '{"text":"[\n  {\n    \"id\": \"8f1b2c3d-4e5f-4a6b-8c9d-0e1f2a3b4c5d\",\n    \"email\": \"ada@example.com\",\n    \"created_at\": \"2024-03-01T10:00:00Z\",\n    \"credits\": 120,\n    \"plan\": { \"name\": \"pro\", \"seats\": 5 },\n    \"labels\": [\"beta\"]\n  },\n  {\n    \"id\": \"9a2c3d4e-5f6a-4b7c-8d9e-1f2a3b4c5d6e\",\n    \"email\": \"grace@example.com\",\n    \"created_at\": \"2024-04-12T08:30:00Z\",\n    \"credits\": 99.5,\n    \"plan\": { \"name\": \"free\", \"seats\": 1 },\n    \"labels\": [],\n    \"referred_by\": null\n  }\n]","target":"typescript","root_name":"User"}'

Free, no key, 120 requests a minute. Full endpoint reference

Generated types

Fix the JSON above to generate types.

How the shape was decided

  • Arrays of objects fold into one type. Every element is merged, so ten rows describe the shape better than one.
  • Missing keys become optional. A key absent from any element is marked optional rather than required.
  • Nulls become nullable. A key that is null in one row and a string in another is a nullable string.
  • Numbers widen. An integer in one row and a decimal in another gives a float.

About this tool

Typing a third-party response by hand is a transcription job, and transcription jobs get things wrong quietly. Paste the body you actually received and the shape comes back as code: nested objects become their own named types, and the outermost one takes whatever name you give it.

The part worth pasting a whole array for is the folding. Given a list of rows, the generator merges every element into one type instead of emitting a type per row: a key that appears in some rows and not others comes out optional, a key that is sometimes null comes out nullable, and a field that is an integer in one row and a decimal in another widens to a float. One well-chosen sample of ten rows produces a better type than one row ever can.

Strings that look like a timestamp or a UUID are narrowed where the target has a type for it — Pydantic gets datetime and UUID, Go gets time.Time, JSON Schema gets format: date-time. TypeScript keeps string, because that is what JSON.parse hands you at runtime and pretending otherwise moves the bug rather than fixing it.

Questions

Which targets are supported?
TypeScript interfaces, Pydantic v2 models, Go structs with JSON tags, and JSON Schema (draft 2020-12). The same inferred shape drives all four.
How are optional and required fields decided?
By what the sample shows. In an array of objects, a key present in every element is required; a key missing from any element is optional. A key whose value is null somewhere becomes nullable. That is why a multi-row sample is worth pasting.
Does the Pydantic output run as-is?
Yes. Nested models are emitted before the models that reference them, so there are no forward references to resolve, and optional fields get both a nullable annotation and a default — `str | None = None` rather than the `str = None` that Pydantic v2 rejects.
What happens to keys that are not valid identifiers?
TypeScript quotes them. Pydantic converts them to snake_case and adds a `Field(alias=...)` so the original key still parses. Go renames them and keeps the JSON tag.
Use it as an APIEvery tool here is a public endpoint. Free, no key, 120 requests a minute.Mock data generatorBuild a schema and export rows as JSON, CSV, SQL or NDJSON.

Other tools