Skip to content

🧬 JSON → Type Definition Converter

Paste JSON and instantly generate TypeScript, PHP, Python, Go, and Rust type definitions. Handles nested objects and arrays.

100% Free No signup Browser-only 5 languages Dark mode

💡 Tips

• Nested objects are automatically extracted as separate types.

• Array element types are inferred. Empty arrays become any[] / []interface{} etc.

• null is treated as optional / nullable like string | null.

• Change the root type name from the input above.

🔗 Related Tools

📖 Where people get stuck

Paste JSON and it generates type definitions for TypeScript, PHP, Python, Go, Rust, Kotlin and Swift, extracting nested objects as separate types and inferring element types from arrays. Everything runs in the browser. What can be inferred is only the shape present in the sample you provideda single API response is what came back that time, not the specification. Treat the output as a starting point for hand-editing rather than as a finished artefact.

Case What happens What to do
A type built from one sample does not hold in production Inference works on the assumption that what it saw is all there is. A field absent from the sample therefore does not exist in the type at all, and a field that happened to carry a value is treated as required. Real APIs return different shapes when a search matches nothing, when an error occurs, when permissions are insufficient, and for older records. Enum-like fields are the sharpest case: if the sample only ever showed "active", the type becomes the literal "active", and the moment "archived" arrives the type is a lie. Run several responses through it. Take at least four cases — a normal one, an empty one, an error and a boundary — and compare the types produced; which fields are genuinely required becomes visible. If an OpenAPI specification exists, generate from that instead: openapi-typescript and oapi-codegen work from a description of every shape that can be returned, which is a different level of reliability from inference over samples. And always read what was generated — a type where every field is required and an enum is a single literal is a sign that you fed it one sample.
Empty arrays and nulls determine nothing From "tags": [] there is no way to know the element type; the result is an anything-goes type such as any[], []interface{} or List<Any>, and the benefit of type checking disappears entirely. null is equally uninformative — whether "deleted_at": null is always null or null only this once cannot be told from one sample. More fundamentally, JSON distinguishes a missing key from a key whose value is null, and many type systems blur that distinction — in TypeScript, ?: and | null are not the same thing. When a response contains an empty array, run another response that has elements in it — a single element is enough to fix the type. If you cannot get one, write that array type by hand: think of the output as automating nine tenths and filling in the rest, and the work stops feeling like a burden. For null, only the API documentation can tell you — where an API distinguishes a missing key from a null one, the accurate TypeScript is both at once, as in deleted_at?: string | null. When in doubt, err loose: a loose type checked at runtime is safer than a strict type that throws at runtime.
The numeric type means different things per language JSON has exactly one numeric type — no distinction between integer and decimal, no precision. The generator therefore has to choose something per language: float64 in Go, i64 or f64 in Rust, number in TypeScript. The dangerous case is identifiers: receive a large integer as float64 or number and past two to the fifty-third the precision is gone and the value is silently rewritten. 9007199254740993 becoming 9007199254740992 raises no error. Date-shaped strings, naturally, remain plain string. Always fix the types of identifiers, money and timestamps by hand after generating. Treating an identifier as a string is safest — there is no reason to hold a value you never do arithmetic on as a number, and indeed the Twitter and Discord APIs return large ids as strings. Never hold money in floating point: for the same reason 0.1 + 0.2 is not 0.3, use an integer in the smallest unit, or your language decimal type. Converting timestamps from string to a proper date type makes the type system force you to handle the time zone. Read the generated type line by line and ask, do I do arithmetic on this value? — if not, a string is fine.

Do not treat a generated type as a trustworthy boundary. TypeScript types in particular exist only at compile time and verify nothing at runtime — write await res.json() as User and the compiler believes it is a User whatever actually came back. That is not a flaw in the type system but a design in which validating at the boundary is a different layer job. For data arriving from outside — API responses, form input — always add runtime validation such as zod or valibot; the type can be derived from the schema, so nothing is maintained twice. Go json.Unmarshal and Rust serde do validate and are safer, but by default they silently discard unknown fieldsDisallowUnknownFields in Go and #[serde(deny_unknown_fields)] in Rust let you notice when the API changes.

📖 How to Use

  1. 1
    Enter or paste JSON
    Paste JSON into the left input field. Use the Sample button to quickly load example data.
  2. 2
    Select target language
    Choose TypeScript, PHP, Python, Go, Rust, Kotlin, or Swift, and optionally change the root type name.
  3. 3
    Copy and use the type definition
    The generated type definition appears on the right. Copy it to your clipboard and paste it into your code.

❓ Frequently Asked Questions

How are nested objects handled?
Nested objects are automatically extracted as separate type definitions and referenced by name.
How are null fields typed?
null fields are treated as optional/nullable. Depending on the language they become Optional, ?, pointer type, etc.
Does it handle a top-level JSON array?
Yes. If the root is an array, it is automatically wrapped as { items: [...] } for type generation.
🐛 Found a bug or issue with this tool?

Free to use, no signup. Even just the steps to reproduce are helpful. Reports go directly to the operator and help us fix issues.

* Browser info (UA / screen / language / URL) is sent automatically to help reproduce the issue