Paste a payload, get clean interfaces — entirely in your browser
interfaces, arrays of objects merge into one item interface, mixed arrays become unions like (string | number)[], and nulls become null (or any with strict mode off). Nothing is uploaded — the engine is client-side and Apache-2.0 licensed.
// paste JSON and press Generate
| JSON input | TypeScript output | Notes |
|---|---|---|
"hello" | string | |
42, 3.14 | number | JSON has no int/float split |
true | boolean | |
null | null (strict) / any (loose) | JSON has no undefined |
["a","b"] | string[] | Single element type |
[1,"two",true] | (boolean | number | string)[] | Union of distinct types |
[{"id":1},{"id":2}] | ItemsItem[] + merged interface | All keys across elements, unioned per field |
[] | unknown[] | Empty array carries no evidence |
| nested object | Named interface, e.g. RootAddress | One interface per object path |
Names are derived from the key path (root "address" becomes RootAddress; an array under "orders" becomes RootOrdersItem). Name collisions get a numeric suffix. The engine never uploads data: parsing and generation are plain client-side JavaScript, licensed Apache-2.0.
Every typed codebase starts the same way: an API payload, a config file, a fixture, and a hand-written interface that drifts out of sync with all three. Sample-to-type generation fixes the drift at the source: paste what the server actually sent, get the shape it implies, and adjust from there.
It parses your JSON (a parse error shows inline instead of output), then walks the structure depth-first. Objects emit interfaces named for their key path. Arrays collect the distinct types of their elements: one type becomes T[], several become a sorted union in parentheses, and arrays whose elements are all objects merge into a single item interface that unions each field across elements — so an orders array with inconsistent keys still yields one honest type. Nulls stay visible as null unless you switch to loose mode, which drops null from unions and emits any for bare nulls, matching how data behaves with strictNullChecks off.
Paste a representative payload — the bigger the sample, the better the merge, since more elements means more keys discovered per array. Pick a root name that fits your codebase (ApiResponse, User, Config). Generate, copy, and paste into a .ts file. Two manual passes are usually worth it afterwards: mark fields that are genuinely optional (a sample can't prove absence), and brand or parse any string field that's secretly a date.
The default payload generates exactly this output (interface mode, strict nulls):
interface Root {
id: number;
name: string;
email: string;
active: boolean;
score: null;
tags: string[];
address: RootAddress;
orders: RootOrdersItem[];
}
interface RootAddress {
street: string;
city: string;
zip: null;
}
interface RootOrdersItem {
id: number;
total: number;
items: string[];
}
Switch to loose mode and the two null fields become any, with every other line unchanged. Notice the two design decisions worth knowing: null is preserved rather than collapsed, because pretending a nullable field isn't nullable is how runtime crashes happen; and the orders array became one merged RootOrdersItem rather than a union of two near-identical shapes, because that's the type you actually want to program against.
Paste a sample payload into the converter and it walks the structure: objects become named interfaces, arrays become T[] or a merged interface for arrays of objects, and mixed arrays become a union of the distinct types. Copy the output into a .ts file and adjust field names or optionality to taste. The whole thing runs in your browser, so API payloads never leave your machine.
For plain data shapes they compile identically, so it's style. Interfaces support declaration merging (two declarations of the same name combine), which is useful if you want to extend generated types elsewhere in the codebase without editing the file; type aliases don't merge but can express unions and tuples. Most teams keep generated output as interfaces.
JSON has null but no undefined, so nulls appear as a null type in the output: score: null. With strictNullChecks off, the converter emits any instead, and unions like string | null collapse to string. If a field is sometimes missing across sample objects, the generator unions the types it actually saw — but a sample can't prove a field is optional, so mark those yourself.
JSON has no date type; dates arrive as ISO strings. The honest inferred type is string. If you know a string field is a date, narrow it to a branded type or parse it with new Date(...) at the API boundary rather than typing it as Date in the raw payload interface.
No. Parsing and type generation run entirely in your browser with plain JavaScript — there is no server call, no logging, and no telemetry on your payload. The generation engine is open source under Apache-2.0, and the types it emits are yours with no attribution required.