How to Convert JSON to TypeScript Interfaces (Generate Types Automatically)
You're wiring up a third-party API and the docs hand you a JSON example response — 200 lines deep, half a dozen nested objects, arrays inside arrays. You can either spend twenty minutes hand-typing the TypeScript interfaces and inevitably miss a field, or paste the JSON into a generator and get the types in two seconds.
In this guide you'll learn how to convert JSON to TypeScript interfaces automatically using PDFFlare's JSON to TypeScript tool — how it handles nested shapes, mixed-type arrays, and optional fields, plus where the generator falls short and what to fix by hand.
Why Generate TypeScript Types From JSON?
A typed API response unlocks four big wins:
- Autocomplete in your editor: Type
response.and your IDE shows every field. No flipping back to the docs. - Compile-time safety: Renaming a field? TypeScript flags every consumer. Mistyping
response.useridinstead ofresponse.userId? The compiler catches it before runtime. - Refactor confidence: Restructuring data flow with types is dramatically safer than without. The compiler is the test suite.
- Self-documenting code:The interface is the contract. Future-you (and teammates) doesn't need to read the API docs to understand the shape.
How to Convert JSON to TypeScript Interfaces (Step by Step)
PDFFlare's generator runs entirely in your browser — your JSON (potentially containing API tokens, customer data, or production payloads) never uploads anywhere.
- Open PDFFlare's JSON to TypeScript tool — no signup.
- Paste a sample JSON response into the input pane. One representative example is enough — the generator infers types from it.
- Click Convert. The output pane shows clean TypeScript interfaces, one per nested shape, with sensible names like
RootObject,Address,OrderItem. - Copy and paste into your codebase. Drop the output into a
types.tsfile and import where you need. - Tweak the names if you want — interfaces auto-named from key names; rename to match your codebase conventions.
How the Generator Decides Types
The mapping from JSON to TypeScript is mostly mechanical, but a few rules are worth knowing:
- JSON string → TS
string - JSON number → TS
number(TypeScript has no separate int / float) - JSON boolean → TS
boolean - JSON null → TS
null(you may want to widen toT | nullby hand) - JSON array of T → TS
T[] - JSON object → TS
interfacewith a property per key
How Mixed-Type Arrays Are Handled
A common API gotcha: an array contains items of different shapes. The generator detects this and emits a union type. For example, [{ "kind": "user", "name": "alice" }, { "kind": "bot", "id": 7 }] becomes (User | Bot)[], with each shape getting its own interface. You then narrow on kind at the consumer.
How Nested Objects Become Sub-Interfaces
Nested objects don't become inline types — they get their own named interface. So { "user": { "address": { "city": "NYC" } } } generates three interfaces: RootObject containing a user: User, User containing an address: Address, and Address with city: string. Easy to import individually, easy to extend.
Where the Generator Falls Short (Fix by Hand)
Type inference from a single example has limits. After generating, adjust these by hand:
Optional Fields
A field that's present in your sample is typed as required. If the API can omit it, mark it optional with ?:. For example, change avatar: string; to avatar?: string;.
Nullable Fields
A field that's null in your sample becomes null in the type — but most fields that can be null can also be a real value. Widen to T | null manually: avatar: string | null;.
String Literal Unions
Status fields like "status": "pending" become string. If the API returns a small, known set of values, tighten to a literal union: status: "pending" | "active" | "closed";.
Empty Arrays
An empty array [] in the sample becomes never[]because there's nothing to infer from. Replace with the actual element type once you know it (e.g. tags: string[]).
Maps With Dynamic Keys
If an object is really a map (keys are dynamic IDs, not a fixed schema), the generator emits one interface per known key. Replace with an index signature: [id: string]: ItemValue.
A Worked Example: Typing a Real API Response
Suppose you're wiring up a webhook from a CRM. The example payload looks like this:
{ "event": "contact.created", "data": { "id": 42, "email": "alice@example.com", "tags": ["lead","priority"], "owner": null }, "timestamp": "2026-05-01T08:00:00Z" }
Pasted into the generator, you get something close to:
RootObjectwithevent: string; data: Data; timestamp: string;Datawithid: number; email: string; tags: string[]; owner: null;
Three things are worth fixing by hand here:
eventis a discriminator. The webhook sends a small known set of event names. Tighten to a literal union:event: "contact.created" | "contact.updated" | "contact.deleted";. Now your switch statement is exhaustive.owneris nullable, not always null. Widen toowner: User | null;once you know the non-null shape. The current type makes it impossible to ever assign a real user.timestampis a string, but it's an ISO 8601 date. If you parse it to aDateon receipt, type the parsed shape: keep the wire type asstringfor the raw payload, then convert.
Sample-Based vs Schema-Based Type Generation
PDFFlare's tool infers types from a single sample. There's a different approach: generate types from a JSON Schema (or OpenAPI) document. Trade-offs:
- Sample-based: Fast, zero-setup, works when you only have one example payload. The downside: required vs optional fields are guesswork, and you only see the shape that one sample happens to have.
- Schema-based (e.g. quicktype, openapi-typescript): Definitive — the schema declares which fields are optional, which are nullable, which have enum constraints. The downside: you need a schema, which not all APIs publish.
A pragmatic workflow: use sample-based generation as the starting point, then evolve toward schema-based if the API publishes a schema (or generate one yourself with PDFFlare's JSON Schema tool).
Runtime Validation: Types Don't Help in Production
TypeScript erases all types at runtime. If the API returns malformed data (a missing field, a wrong type), your typed code happily proceeds and crashes somewhere downstream with a confusing error. The fix: add a runtime validator at every API boundary. Options:
- JSON Schema validation— generate a schema with PDFFlare's JSON Schema tool, validate at the boundary with AJV. Same source-of-truth for types and runtime checks.
- Zod / io-ts — define a single schema in TypeScript that produces both the type and a runtime parser. Slightly more ceremony than sample-based generation, but bulletproof.
- Hand-written guards — for tiny APIs, just
typeofchecks. Doesn't scale, but works.
Common Scenarios
Typing a Third-Party API
You're hitting a REST API and the docs only give a JSON example. Drop it in the generator, get an interface set, type your fetch wrapper. Done in under a minute. If you also want a runtime check, generate a JSON Schema with PDFFlare's JSON Schema tool and validate at the boundary.
GraphQL Response Types
If you're on GraphQL, codegen tools like graphql-codegen give you types automatically. But for one-off queries or non-codegen workflows, paste a sample response into the JSON to TypeScript tool — fast and dependency-free.
Local Storage and IndexedDB Schemas
When you read JSON back from localStorage or IndexedDB, you need a type for it. Generate from your write payload, save the interface, and now your reads are type-safe.
Webhook Payload Types
Stripe, GitHub, Slack, and other webhook providers document payload shapes as JSON examples. Paste the example, generate the type, drop into your handler. Add the optional ?: markers based on which fields the docs say are nullable.
Best Practices
- Use the most representative sample. A response with all optional fields populated produces better types than a minimal one. Run a real query and use that.
- Sort keys before generating. Run the JSON through PDFFlare's JSON Formatter with Sort Keys on. Stable ordering means stable interface ordering when you regenerate.
- Validate at runtime, not just compile time. Types are erased at runtime — bad data still gets through. Pair the interface with a JSON Schema or Zod validator at the API boundary.
- Check the generator output.Don't blindly paste — read the interfaces, mark optional fields, fix string literal unions, widen nulls.
Naming Generated Interfaces Cleanly
The generator picks names like RootObject, Data, Item. Functional, but generic. Three quick rename patterns improve readability:
- Name the root after the operation, not the data.
GetUserResponseis more useful thanRootObjectwhen you have several similar interfaces in one file. - Name nested types after the parent key. A nested
addressobject becomesAddress; a nestedpreferencesbecomesPreferences. The generator does this most of the time. - Suffix array element types with their role. An
items: Item[]field is fine, butitems: OrderItem[]tells the reader what kind of items at a glance.
Generated Types vs Hand-Written Types
Generated types are a fast starting point, not the final answer. A few cases where hand-written wins:
- Discriminated unions. A polymorphic API response keyed by a discriminator (
kind,type,__typename) is far more useful as a hand-written tagged union with literal types than as a generic union. - Branded primitives. An
idfield is technically anumber, but you don't want to accidentally pass anorderIdwhere auserIdis expected. A branded type (type UserId = number & { __brand: "UserId" }) catches this — the generator can't infer it. - Aliased imports for shared shapes.If two endpoints return the same nested shape, generate once and import everywhere. Don't paste the same interface into multiple files.
Privacy: Your JSON Stays on Your Device
PDFFlare's JSON to TypeScript tool runs entirely in your browser. The inference logic is JavaScript executed locally — your JSON never uploads to any server. Production payloads, API tokens, customer data are all safe to paste.
Wrapping Up
Hand-typing TypeScript interfaces from a JSON example is a chore that a generator does in two seconds. Generate, then spend the saved time on the parts that need human judgment: optional fields, string literal unions, nullability. The result is a typed API integration that catches bugs at compile time instead of in production.
Got a JSON sample that needs types? Open PDFFlare's JSON to TypeScript tool and you'll have interfaces in your editor before your coffee finishes brewing.
Related Tools
- JSON Schema — generate a runtime validator from a sample
- JSON to Go — generate Go structs the same way
- JSON to Python — generate Python @dataclass types
- JSON Formatter — format and sort JSON before generating