JSON to TypeScript Converter
Paste any JSON and get back matching TypeScript interfaces — nested objects become their own named types, and arrays of objects are merged into one shape with optional fields detected automatically.
Interactive Client Prototype Sandbox
Nested objects become their own named interface; an array of objects is merged into one shape, with a field marked optional (?) if it's missing from at least one item. Runs entirely in your browser — nothing is uploaded.
Disclaimer: This free tool is provided “as is,” without warranties of any kind, and is for general informational purposes only — not professional, legal, financial, medical, tax, or engineering advice. Results may contain errors; verify anything important independently and use at your own risk. We accept no liability for any loss or damage arising from its use. See our Terms of Use for details.
Step-by-Step Guide
Paste a JSON object or array into the input panel — a real API response works best, since the converter infers types directly from the values it sees. Set a root interface name if you don't want the default 'Root', and choose between `interface` and `type` output depending on your project's style.
The output panel updates live. Nested objects (like an `address` or `user` field) get their own interface named after that field, referenced from the parent rather than inlined — this keeps the output readable and matches how most TypeScript codebases are actually structured.
When the root or a field is an array of objects, every item in the array is merged into one shape: a key present in some items but not others is marked optional with `?`, and a key whose value type differs between items (say, a `value` field that's sometimes a number and sometimes a string) becomes a union type like `number | string`. This is the main advantage over typing from a single example — a real API often omits fields that are simply null or empty, and only an array with several real items reveals that pattern.
Reading the output correctly
The generated types describe the shape you pasted, not necessarily the full contract of the API — if the sample JSON happens not to include an edge case (a field that's sometimes an array, a rare error shape), the generated interface won't know about it. Treat the output as a strong starting point to refine, not a guaranteed schema, especially for endpoints you don't control.
Input `[{"id":1,"address":{"city":"NYC"}},{"id":2,"address":{"city":"LA","zip":"90001"}}]` produces:
export interface Address { city: string; zip?: string; }
export interface RootItem { id: number; address: Address; }
export type Root = RootItem[];
Who it's for
TypeScript developers wiring up a new API response, writing a fetch wrapper, or typing a JSON config file without hand-writing every field.
Core Features
- Converts a JSON object or array into one or more TypeScript interfaces (or type aliases).
- Nested objects become their own named interface instead of one deeply inlined blob.
- An array of objects is merged into a single shape — a field missing from even one item is marked optional (?), and a field with different types across items becomes a union.
- Custom root interface name, and a toggle between `interface` and `type` output.
- Runs entirely in your browser — paste a real (possibly sensitive) API response without it ever leaving your device.
🛡️ No tracking — your inputs, keys, and details never leave this client sandbox.
Related tools
Why does it generate a separate interface for a nested object instead of inlining it?
Naming nested shapes (like `Address` extracted from a `user.address` field) matches how TypeScript code is normally written and keeps the output readable — a deeply inlined type with several levels of nested object literals is much harder to read and reuse than a handful of small, named interfaces referencing each other.
How does it decide a field is optional?
Only when converting an array of objects: if a key is present in some array items but missing from at least one other item, it's marked optional (`?`) on the merged interface. A single object (not an array) has no way to reveal optionality from one example alone, so every field on a lone object is generated as required.
Why is a field typed as a union like `number | string`?
When merging an array of objects, if the same key holds different JSON types across different items (for example, an ID that's sometimes a number and sometimes a numeric string), the generated field type is the union of every type actually observed, rather than picking one arbitrarily and silently dropping the other.
Does this validate that my JSON matches a schema?
No — it only describes the shape of the specific JSON you pasted. It doesn't know about fields your sample happens not to include, and it can't guarantee the API will always return this exact shape. For runtime validation against a schema, pair the generated types with a validation library separately; this tool only handles the type-generation step.
Is my JSON uploaded anywhere?
No. Parsing and type generation both happen in your browser using plain JavaScript — this matters because API responses often contain real user data, internal field names, or other details you may not want touching a third-party server just to generate a type definition.
Why hand-writing API types goes wrong
Typing an API response by hand means reading through a JSON payload, mentally categorizing each field's type, and writing it out as an interface — a process that's tedious for a small object and effectively infeasible to do correctly for a large, deeply nested one. The failure mode is rarely a dramatic type error; it's subtler and more common: a field gets typed as always-present when the API actually omits it under certain conditions, and the resulting code compiles fine until the day that field is genuinely missing at runtime and something downstream reads `undefined.someProperty`.
Why merging matters more than a single example
Most 'paste one example, get a type' converters only look at a single object, which means they can only be as complete as that one example happens to be. A field that's optional in the real API — present on most records but absent on a handful of edge cases — will look required if the one example you happened to paste includes it. Generating types from an array of real items and merging their shapes together, rather than reading just the first one, is what actually surfaces optionality: if 9 out of 10 sample records have a `discount` field and one doesn't, the generated type correctly marks it `discount?:` instead of lying that every record has it.
The limits of inference from data
Generating types from example data is fundamentally different from generating them from a real schema (like an OpenAPI spec or a database definition) — it can only describe what it observed, not what's actually guaranteed by the API contract. A field that happens to always be a positive integer in your sample will simply be typed `number`, with no indication that negative values or zero are invalid; a field that's always present in your sample but genuinely optional in rare cases will be typed as required. This is why generated types are best treated as an accurate starting draft assembled from real data, not a substitute for an authoritative schema when one is available.
Where this fits in a typical workflow
The most common real use is immediately after inspecting a new API endpoint for the first time: copy a response from the browser's network tab or an API client, generate the interface, paste it into the codebase, and refine from there — renaming the auto-generated root type, splitting or merging nested interfaces to match existing naming conventions, and tightening any field that inference left too loose (like a string that's actually always one of a fixed set of values, which would be better expressed as a union of string literals than a bare `string`).