JSON to TypeScript
Turn any JSON payload into clean TypeScript interfaces.
export interface Location {
city: string
country: string
}
export interface Profile {
title: string
location: Location
}
export interface Project {
name: string
stars: number
archived?: boolean
}
export interface Root {
id: number
name: string
isActive: boolean
roles: string[]
profile: Profile
projects: Project[]
}Why convert JSON to TypeScript?
Almost every app talks to an API that returns JSON, and every one of those responses has a shape you probably want to describe with a TypeScript interface. Writing those interfaces by hand is tedious and error-prone — miss one optional field and you get runtime surprises that types were supposed to prevent.
This converter takes a real JSON payload and generates accurate, ready-to-paste interfaces in seconds. You get compile-time safety, better editor autocompletion, and a single source of truth for the data your code depends on.
There is a second, quieter benefit. Generating types from a real response tells you what the API actually returns, which is not always what its documentation claims. Fields that arrive as strings rather than numbers, timestamps in an unexpected format, and objects that are sometimes null all become visible the moment you look at the generated interface.
How to use it
Paste a JSON object or API response into the input on the left, optionally rename the root interface, and the TypeScript appears instantly on the right. Use Format JSON to tidy messy input, then Copy the generated types straight into your project. Everything runs in your browser, so it is safe to paste private payloads.
city: string
}
interface Root {
id: number
name: string
tags: string[]
profile: Profile
}
How types are inferred
| JSON value | TypeScript type |
|---|---|
| "hello" | string |
| 42 / 3.14 | number |
| true / false | boolean |
| null | null |
| { … } | A named, nested interface |
| [ { … } ] | A merged interface, as Item[] |
| [1, "x"] | (number | string)[] |
| [] | unknown[] — an empty array carries no information |
| missing in some rows | field?: — marked optional |
The rule underneath all of this is simple: the tool describes the sample you gave it, as precisely as that sample allows. It cannot know about a field that never appeared, and it cannot know that a number field is really an enum of three values. That is a limitation of inference, not a bug — and it is why the sample you choose matters.
Tips for the cleanest output
Give it a representative sample
A single record produces a single record’s worth of truth. If a field is sometimes absent or sometimes null, paste an array containing both cases — the tool merges the objects and marks the field optional or nullable accordingly. A three-element array showing the variation you actually expect is worth far more than one perfect example.
Name the root interface
Rename the root to something meaningful, such as User or ApiResponse, before copying. Nested interfaces are named from their keys, so a good root name makes the whole generated block read naturally in your codebase.
Strip the envelope if you only want the payload
Many APIs wrap results in { data, meta, errors }. If you only care about the item type, paste just the inner object — you will get a tighter interface without having to delete the wrapper afterwards.
Watch out for empty arrays and all-null fields
An empty array cannot tell the tool what it will eventually contain, and a field that is null in every sample will be typed as null alone. Both are places where you should edit the generated type by hand — usually to Something[] or string | null.
What generated types cannot tell you
Generated interfaces are a large head start, not a finished contract. A few things are worth adjusting by hand afterwards:
- Dates are strings. JSON has no date type, so
"2026-08-18T09:00:00Z"infers asstring. Narrow it to a branded type or convert at the boundary if precision matters. - Enums look like plain strings. A
statusfield that can only be"active"or"archived"infers asstring. Tightening it to a union of literals is usually the single most valuable manual edit you can make. - Integers and floats are both numbers. TypeScript has one numeric type, so any distinction has to live in a comment or a runtime check.
- Large integers lose precision. IDs beyond the safe integer range are typically sent as strings by well-designed APIs; if yours sends them as numbers, treat that as a bug to raise rather than a type to model.
- Types are not validation. An interface disappears at compile time and guarantees nothing about the bytes that arrive at runtime. If the source is untrusted or unstable, parse with a runtime validator and derive the type from that schema instead.
Where this fits in a real workflow
If your API publishes an OpenAPI or GraphQL schema, generating types from that schema in your build is strictly better — it stays in sync automatically and covers every endpoint, not just the one you sampled. This tool is for everything else: a third-party API with no published schema, a webhook payload you received once, a legacy endpoint nobody documented, or a quick sanity check on what an API returns before you commit to an integration. Those cases are common enough that a fast manual converter earns its place alongside a generated client.
Verify before you depend on it
Generated interfaces describe the sample you provided, not every response the API can return. Review them against the API’s documentation, and add runtime validation for any data you do not control. Your JSON is processed entirely in your browser and is never uploaded — see the privacy policy and disclaimer.