How to use it
- Paste sample JSON on the left. The more complete the sample the better: several different records in an array let the tool see which fields are optional.
- Enter a name for the root type, such as User or OrderResponse.
- Choose TypeScript interfaces or a Zod schema. The code appears on the right as you type; copy it or download a .ts file.
- Review the result, especially fields whose sample value is null or an empty array, and fill in the real types.
How types are inferred
Basic types and nesting
JSON strings, numbers, true or false and null become string, number, boolean and null. Each nested object gets its own interface named after its key in PascalCase: owner becomes Owner. Array item types use the singular: items gives Item, categories gives Category and boxes gives Box, while words ending in ss or us, such as status, are left alone.
Merging objects in arrays
API arrays often contain records where some have a field and some do not. The tool merges all objects in an array into one interface: fields present in every item are required, and fields present in only some get a question mark after the name, TypeScript's syntax for optional properties. A field with different types in different records becomes a union — qty that is sometimes a number and sometimes null becomes number | null — and a mixed array becomes (number | string)[].
Name clashes and reuse
Objects with exactly the same structure share one interface instead of producing duplicates. If two different structures would get the same name, the second gets a number, such as User and User2; rename them to suit your domain. Keys that are not valid JavaScript identifiers, such as first-name or 2fa, are quoted.
Zod schema
In Zod mode each interface becomes a z.object, optional fields get .optional(), and schemas are defined before they are used. The last line uses z.infer to derive a type with the same name from the schema, so types and runtime validation come from one definition. Install zod in your project to use it.
Examples
With the sample loaded and the root type named User, the result is:
export interface User {
id: number;
name: string;
email: null;
roles: string[];
orders: Order[];
}
export interface Order {
id: number;
total: number;
items: Item[];
coupon?: string;
}
export interface Item {
sku: string;
qty: number;
}Only the second order has a coupon, so coupon is optional. The second order's items array is empty, and merged with the first it is still Item[]. email only appears as null in the sample, so the tool can only infer null; in reality it is probably string | null, which is exactly the kind of thing to check by hand.
Limits
- Types come from the sample only. Fields or value types that do not appear in it are not in the result.
- A field that is only ever null is typed null, and a field that is only ever an empty array is typed unknown[]; fill these in yourself.
- Dates, enums and string formats are not recognised: "2026-09-30" is a string and "admin" does not become a literal type.
- Integers above 2^53 lose precision in JavaScript and are still typed number; APIs that send large integers as strings will show string in the sample.
Frequently asked questions
How are optional fields detected?
From objects in arrays: a field present in only some of them is optional. Fields of a single object are treated as required.
Why is a field typed null?
Its only value in the sample was null, so nothing else can be inferred. Change it to string | null or whatever it really is.
Interface or Zod schema?
Interfaces for compile-time checking only; a Zod schema when you also want to validate API data at runtime, with z.infer giving you the same type.
Do repeated structures create several interfaces?
No. Identical structures share one interface.
Is my JSON uploaded?
No. Everything is inferred in your browser.