JSON to TypeScript Interface Generator

Paste any JSON object and get a fully-typed TypeScript interface — or a set of nested interfaces — generated instantly in your browser. Handles nested objects, arrays, optional properties, union types and null. Nothing is uploaded. Last reviewed 2026-06-19.

How it works

  • Parse — your JSON is parsed with the browser's native JSON.parse. If it is not valid JSON, the error message is shown immediately.
  • Infer — the value tree is walked recursively. Each object becomes a named interface. For arrays, the type is inferred from all elements so the resulting type covers every item. Keys whose value is null, or that are absent from some array elements, are marked optional with ?.
  • Emit — interfaces are output deepest-first (child before parent) so the file compiles top-to-bottom without forward references. Each interface is exported, ready to paste into any .ts or .d.ts file.

When properties become optional

Two conditions cause a property to receive the optional marker (?):

  • The value in the sample JSON is null — the generator adds ? and appends | null to the type, because the real API may return either the value or nothing.
  • The JSON contains an array of objects and a key appears in some elements but not all — the key is added to the merged interface but marked ?, because not every record will have it.

If you know a field is always present and never null, simply remove the ? from the generated output.

JSON → TypeScript type mapping

JSON valueTypeScript typeExample JSON
string string "Alice"
number number 42 or 3.14
boolean boolean true or false
null T | null (+ optional ?) null
array of T T[] ["a","b"]
array of mixed primitives (string | number | boolean)[] [1,"x",true]
object interface Name { … } { "city": "NYC" }
unknown / empty array unknown[] []

Interface naming

Interface names are derived from the JSON key name and converted to PascalCase — for example, a key user_profile produces an interface called UserProfile, and lineItems produces LineItems. The root object always uses the name from the Root interface name field above (default Root). Rename it to match your domain model — for example, User, ApiResponse, or Product.

Privacy & security

All processing happens entirely inside your browser — no data is sent to any server, no cookies are set, and nothing is logged. It is safe to paste real API responses, including those with personal data, because the content never leaves your device. The tool also works offline once the page has loaded.

What TypeScript is, and why types help

TypeScript is a typed superset of JavaScript created at Microsoft by Anders Hejlsberg (the designer of C# and Turbo Pascal) and first released in 2012. Every valid JavaScript program is already valid TypeScript; what TypeScript adds is a static type layer that the compiler checks before your code ever runs, then erases entirely — the browser still receives plain JavaScript. The payoff is that a whole class of bugs is caught while you type: a misspelled property, a number used where a string was expected, a field that might be undefined. Editors use the same type information to power autocomplete, inline documentation and safe automated refactoring.

TypeScript uses structural typing ("duck typing"): two types are compatible if their shapes match, regardless of their names. An object is acceptable wherever an interface is expected as long as it has at least the required properties of the right types. That is why a single, accurate interface generated from a real API response is so valuable — it describes the exact shape your code can rely on.

Why generate types from JSON?

When you consume a JSON API, the response is just untyped data — your editor knows nothing about it, so every response.user.name is a guess that only fails at runtime. Generating an interface turns that response into a contract: the compiler now knows which fields exist and what type each holds, autocompletes them as you type, and flags response.user.naem as an error immediately. Doing this by hand for a deeply nested payload is tedious and easy to get wrong, which is exactly the job this tool automates — it walks the JSON once and emits accurate, nested, exported interfaces you can paste straight into your project.

interface vs type alias

TypeScript offers two ways to name an object shape: an interface and a type alias. For plain object shapes they are largely interchangeable, and this generator emits interface declarations because they read cleanly and can be extended and merged. Reach for a type alias when you need something interfaces cannot express directly: unions (type Status = "active" | "archived"), tuples, mapped types, or aliasing a primitive. A common convention is "interfaces for the public shape of objects, type aliases for unions and utility types" — but consistency within a codebase matters more than the exact choice.

The limits of inferring types from one sample

This is the most important thing to understand about any JSON-to-types tool, including this one: an interface is inferred from the single example you paste, and one example cannot reveal everything about an API. If a field is sometimes present and sometimes absent but your sample happens to include it, the generator will mark it required. If a field is usually a number but occasionally null, only a sample that contains the null will produce the optional, nullable type. An empty array gives no element type at all, so it can only be typed as unknown[]. And a string that is really an ISO date, an email or an enumerated value is simply typed as string, because at the JSON level that is all it is. Treat generated types as an excellent first draft to refine against the API's real documentation, not as a guaranteed complete contract.

null, undefined and the optional ? mark

TypeScript draws a careful distinction that JavaScript blurs. null is an explicit "no value"; undefined is "this was never set"; and the optional marker ? means the property may be missing from the object entirely. These are not the same thing. When you enable the recommended strictNullChecks compiler option, the type system forces you to handle each case, which prevents the classic "cannot read property of undefined" crash. This generator adds ? (and appends | null) when a sampled value is null, and adds ? alone when a key is absent from some elements of an array of objects — a faithful reflection of what the sample showed. If your domain knowledge says a field is always present, simply delete the ? from the output.

any vs unknown

When a type genuinely cannot be determined, you have two escape hatches. any switches type checking off for that value — anything is allowed, which quietly reopens the door to the very bugs TypeScript exists to catch. unknown is the safe alternative: it accepts any value but forces you to narrow it with a check before you use it. Modern style strongly prefers unknown over any, and that is why this tool emits unknown[] for an empty array rather than any[] — it keeps your code honest until you supply a real element type.

Types vanish at runtime — validate untrusted data

Because TypeScript types are erased during compilation, they offer no protection at runtime. If a server returns data that does not match your interface — a missing field, a string where you expected a number — TypeScript cannot stop it, because by then the types no longer exist. For data crossing a trust boundary (an external API, user input, a webhook) you need a runtime validator. Libraries such as Zod, io-ts and Valibot let you declare a schema once and both validate incoming data and infer the matching TypeScript type from it, so the static type and the runtime check can never drift apart. JSON Schema with a validator like Ajv does the same job in a language-neutral way. The interfaces this tool produces describe the happy-path shape; a runtime validator guarantees the data actually arrived in it.

Sample-based vs schema-based generation

Generating types from a sample, as here, is the fastest path when all you have is an example response — no setup, no build step, paste and go. When an API publishes a formal description you can do better: an OpenAPI (Swagger) document or a GraphQL schema can be fed to a code generator that produces types covering every endpoint and every variant the API documents, and that can be re-run whenever the API changes so the types never go stale. Think of sample-based generation as the quick, ad-hoc tool and schema-based generation as the maintained, whole-API solution — they complement each other rather than compete.

From generated draft to production type

A few quick edits turn a generated interface into a polished domain type. Rename the root interface from Root to something meaningful (User, ApiResponse, Invoice). Tighten loose string fields into literal unions where the value set is known ("draft" | "published"). Replace unknown[] with the real element type once you know it. Consider "branding" identifiers so a UserId and an OrderId cannot be mixed up even though both are strings. And if you are shipping a library, move the interfaces into a .d.ts declaration file — a types-only file that describes shapes without emitting any JavaScript — so consumers get full type information at zero runtime cost.

How arrays of objects become a single interface

When a JSON array contains objects, this tool does not generate a separate type for each element — it merges them into one interface that describes the whole collection. It gathers every key that appears across all the objects, infers each property's type from the values it sees, and marks any key that is missing from at least one element as optional with ?. The property is then typed as an array of that merged interface (for example users: User[]). This is usually what you want, because a real API list is meant to hold items of one shape — but it also means a single odd element can widen the inferred type, so it is worth pasting a representative sample rather than just the first record.

Enums and literal unions

JSON has no concept of an enum, so a field whose value is one of a fixed set — a status, a role, a country code — arrives as a plain string, and that is how this tool types it. Tightening such fields by hand is one of the highest-value edits you can make: change status: string to status: "draft" | "published" | "archived" and the compiler will now catch any typo or invalid value, while your editor autocompletes the allowed options. TypeScript also has a dedicated enum keyword, but most modern codebases prefer literal-union types like the one above, because they are simpler, erase cleanly to plain strings, and play nicely with JSON.

Utility types worth knowing

Once you have an accurate interface, TypeScript's built-in utility types let you reshape it without rewriting it. Partial makes every property optional (handy for an "update" payload where any field may be sent); Required does the reverse; Pick and Omit build a smaller type from a few fields of a larger one; Readonly prevents mutation; and Record describes a dictionary keyed by string. Generating the base interface here and then deriving these variations from it keeps your types DRY — one source of truth, many shapes — so a change to the underlying data shape only has to be made in one place.

A practical workflow

A reliable pattern is: call the real API once, copy a representative response, paste it here, and rename the root interface to match the endpoint. Tighten obvious enum-like strings into literal unions, confirm the optional markers against the API's documentation, and replace any unknown[] with the real element type. For data that crosses a trust boundary, recreate the same shape as a Zod or JSON Schema validator so the runtime check and the static type stay in sync. Done this way, a JSON sample becomes a fully-typed, validated model in a couple of minutes instead of a tedious hand-translation.

Frequently asked questions

Does this handle deeply nested objects?
Yes. The generator walks the entire JSON tree recursively. Each nested object becomes its own named interface, and parent interfaces reference those child interfaces by name. Interfaces are emitted deepest-first so the output compiles top-to-bottom without forward references.
What happens with arrays of mixed types?
When all elements of an array are primitives (string, number, boolean) the generator produces a union array type such as (string | number)[]. When elements are objects it merges all observed keys across every element — a key present in some elements but not others is marked optional (?) so the type correctly represents all items in the array.
What does the ? (optional) mark mean?
A property marked with ? is optional — it may be absent from some objects in practice. The generator adds ? when a key's value is null in the sample JSON (indicating the real value may be absent), or when a key appears in some but not all elements of an array of objects. In TypeScript, an optional property may be missing from the object altogether — it is distinct from a property that is present but explicitly null.
Can I use this output directly in TypeScript?
Yes. The generated interfaces use standard TypeScript syntax and are exported, so you can paste them directly into a .ts or .d.ts file. You may want to rename interfaces or adjust optionality based on your domain knowledge — the generator infers types from a single sample JSON, so it cannot know which fields are truly required in every case.
How do I handle arrays of objects?
When an array contains objects the generator creates a named interface for the element type — for example a key users: [{...}] produces an interface Users {...} and types the property as users: Users[]. If different objects in the array have different keys, all keys are merged and any key missing from at least one element is marked optional.
What if my JSON has keys that are not valid TypeScript identifiers?
Keys that contain spaces, hyphens, dots, or start with a digit are not valid TypeScript identifiers. The generator detects these and wraps them in quotes — for example "my-key"?: string — which is valid TypeScript object type syntax. You can then access such properties with bracket notation: obj["my-key"].
Can it output a Zod schema or a type alias instead of an interface?
Yes. Use the Output selector above the tool to switch the target to a TypeScript type alias or a Zod v3 schema. The Zod output is built from the same inferred shape — strings become z.string(), numbers z.number(), nested objects z.object({...}), arrays z.array(...) and optional keys get .optional() — and it includes the import { z } from "zod" line so it is ready to paste. Reach for Zod when you need runtime validation, not just compile-time types.

Related tools

See all browser tools → · All developer & data conversions →

Sources and standards

This tool follows the published specification for what it does, rather than a hand-written approximation. The references below are the primary documents it implements — each one is the authority for the rules applied on this page.

Descubre más herramientas

Ver las 70 herramientas →

Pon esta herramienta en tu web — gratis

Todas las herramientas que puedes insertar →

Añade JSON to TypeScript a cualquier página, artículo o plantilla. Es gratis para siempre: sin registro y sin anuncios dentro del widget. Solo te pedimos una cosa: deja visible el pequeño enlace de atribución.

Vista previa del widget