JSON to TypeScript Interface Generator
Generate TypeScript interfaces from JSON online free. Reads every record, marks missing fields optional and null values nullable, and runs entirely in your browser.
Runs in your browserNothing uploadedFree · no signup
Declare as
Unknown values
Every element of an array is read, not just the first, so a field missing from some records becomes optional and a field holding null becomes nullable — two different facts, kept apart. Paste several records rather than one: a single sample cannot show which fields are optional.
Frequently asked questions
- Why should I paste several records instead of one?
- Because a single record cannot tell you which fields are optional. If one object has an email and you generate a type from it, email comes out required - and the first row in production without one fails to compile, or worse, does not. Paste an array of records and every element is read, not just the first: a field that appears in some records and not others becomes optional, and the type then describes the endpoint rather than one lucky response. The tool tells you how many records it read, and says so explicitly when there is only one.
- What is the difference between name?: string and name: string | null?
- They are two different facts about your data and most generators throw one of them away. A question mark means the key may be absent from the object entirely - reading it gives undefined. The union with null means the key is always there but may hold null. A field that does both is written name?: string | null. The distinction is the whole reason strictNullChecks exists: obj.name?.trim() is needed for the first, obj.name !== null for the second, and code that guards the wrong one still crashes. This generator keeps them apart by counting how many records carried each key and looking at the values separately.
- Can it generate string literal unions for status fields?
- Yes, but only with evidence, and it is off by default. Turn on literal unions and a field becomes something like "active" | "archived" when three conditions hold: at least three records carried it, it holds at most twelve distinct values, and at least one value repeats. That last condition is what separates a closed set from free text - three rows with three different values is no evidence of an enum at all, it is just three strings. Anything that fails the test stays string, because a literal union guessed from a small sample is a type that rejects perfectly valid data the first week it is in production.
- Why did two fields end up sharing one interface?
- Because they have the same shape. Interfaces are matched structurally, with field order ignored, so an author and an editor that both hold name and email produce a single interface used twice rather than two identical ones. That is almost always what you want - a real API response would otherwise generate a dozen near-duplicates. When two shapes genuinely differ but want the same name, the second gets a numeric suffix and the tool tells you it happened.
- What does it do with keys that are not valid identifiers?
- Quotes them. A JSON key can be anything - "first name", "2fa", "content-type", even an empty string - and TypeScript only accepts a bare identifier as an unquoted property name, so those are written "first name": string and read back as obj["first name"]. Keys that are valid identifiers are left unquoted. Interface names are a separate problem, because they are derived from keys: they get PascalCased, singularised for arrays (users becomes User[]) and kept away from the built-in type names, since declaring interface Object merges with the standard library rather than shadowing it.
- What about IDs longer than 15 digits?
- They are flagged rather than silently accepted. TypeScript's number is a 64-bit float, so any integer past 2^53 - about 9.007 quadrillion - cannot be held exactly: a 19-digit Twitter or Discord snowflake comes back with its last digits changed. The generator reads your JSON without JSON.parse precisely so it can see the original digits and warn you, and the fix is to type those fields as string or bigint. It is worth checking how the JSON reaches your code too, because JSON.parse damages them before any type is involved.
- Is my JSON uploaded anywhere?
- No. The JSON is parsed and the types are generated entirely in your browser, and nothing is sent to a server. That matters more here than for most converters, because the fastest way to get a type for an API is to paste a real response - and a real response usually holds a customer name, an email address, an internal hostname or a token. None of it leaves your device.