search

Found

info Overview

Paste any JSON and infer key and value types into TypeScript interface or type definitions, with nested objects, arrays, and readonly modifiers.

📘 How to Use

  1. Paste your JSON into the left panel
  2. Pick an output format (interface or type) and a root name
  3. Toggle readonly or optional modifiers as needed

JSON to TypeScript Converter

Copied

Options

Article

JSON to TypeScript Converter | Generate Typed Interfaces from a Sample

Paste a JSON sample and this tool walks its keys and values to infer TypeScript interface or type definitions. Nested objects and arrays become their own named types, and you can add readonly or make every field optional in one click.

💡 About this tool

Anyone who has wired up a third-party API knows the chore: the docs are vague, so you hit the endpoint, get a 40-field JSON blob back, and now you have to hand-write an interface for it. Miss a nested object and TypeScript yells; typo a key and you get a silent any. Doing it by hand for a deeply nested payload is exactly the kind of busywork people post on Stack Overflow asking how to skip.

Drop one representative JSON response in and the converter infers the shape. Strings become string, numbers (int or float) become number, booleans become boolean, null stays null, and arrays take the element type plus []. Each nested object is hoisted into its own definition — a user.address.geo chain turns into Root, Address, and Geo so you can read the model top-down instead of squinting at one giant brace soup. If the root is an array of objects, you get a RootItem type plus a type Root = RootItem[] alias.

Flip between interface and type with the toggle. Add readonly for immutable models, or check "all fields optional" to slap ? on every property when you are typing a partial or a PATCH body. The output is a clean starting point you paste straight into your editor.

🧐 Frequently Asked Questions

Q. How are nested objects handled? Each one is hoisted into a separate type named after its key, capitalized. A profile object inside user becomes a standalone Profile definition, and the parent references it by name instead of inlining it.

Q. How does it infer array types? It reads the first element. [1, 2, 3] becomes number[]; an array of objects produces a SomethingItem type wrapped as an array. An empty array can't be inferred, so it falls back to unknown[].

Q. interface or type — which should I pick? Use interface if you rely on extends or declaration merging; use type if you'll add unions, intersections, or function signatures. For plain object shapes like these, they're interchangeable — pick whatever your lint config prefers.

Q. Why is every number just number? TypeScript has no integer type, so 1 and 1.5 are both number. Likewise dates and IDs come out as string. Treat the output as a draft and narrow to Date or literal/union types where it matters.

Q. What about fields that are sometimes null? If the sample value is null, you get the null type. Real payloads usually mean "string or null", so after generating, widen those to a union like string | null by hand — the sample can only show one shape at a time.

📚 Fun Facts

TypeScript uses structural typing, not nominal: two types are compatible if their shapes match, regardless of name. That's why a generated interface Root slots in anywhere the real type is expected as long as the fields line up — handy, but it also means two semantically different objects with the same shape are silently interchangeable. The community workaround is "branded" types like type UserId = string & { __brand: 'UserId' }, which add a phantom property so a plain string won't sneak in. Sample-driven types are a starting line, not a finish line: you still layer on null-safety, literal unions, and Date conversions before they're production-grade. Tools in this family trace back to json2ts-style generators that popularized "paste JSON, get types" as a workflow years ago.