Guide
From a JSON response to TypeScript types and Zod schemas
Typing API data by hand is slow and error-prone: a field that is sometimes missing gets declared as required, a field that is sometimes null gets declared as a string, and the compiler happily trusts both. This generator reads real JSON, works out the shape of every object in it, and writes TypeScript interfaces or Zod schemas that match what the data actually contains.
How the types are inferred
Each value is classified as a string, number, boolean, null, array or object. Objects become named types: the root gets the name you choose, and nested objects are named after their key, singular for arrays, so orders holds Order items and items holds Item. When two nested objects have exactly the same keys and types, they share one type rather than producing duplicates.
Why more samples give better types
The important part is merging. Every item of every array, and every JSON document you paste as a separate line, is compared. A key that is missing from any of them becomes optional (coupon?: string). A value that is null in any of them gains | null. An integer in one place and a decimal in another become number. With a single sample, every key looks required, so paste a few real responses, ideally including edge cases such as an empty cart or a deleted account.
Optional is not nullable
TypeScript distinguishes a property that may be absent (?) from one that is present but null (| null). APIs use both, and code must handle them differently: optional chaining copes with either, but a JSON serialiser omits undefined and keeps null. The generator keeps the distinction exactly as the samples show it.
interface or type, and readonly
Choose interface for classic declarations, or type aliases if your codebase prefers them; for object shapes they behave the same for almost every purpose. Switch on readonly to mark every property readonly, which suits data you only read from an API and stops accidental mutation.
Adding runtime checks with Zod
Types disappear at runtime, so a changed API can still break your app silently. The Zod output gives you a schema for every object, declared in dependency order, plus export type User = z.infer<typeof UserSchema>, so the schema and the type never drift apart. Whole numbers are checked with .int(), ISO 8601 timestamps with .datetime({ offset: true }) and UUIDs with .uuid(). Call UserSchema.parse(data) at the edge of your app and errors show exactly which field is wrong.
A worked example
The sample user record contains an address with a null unit, two orders and a nested items list. It produces four interfaces — Address, Item, Order and User. Because only the second order has a coupon, Order reads order_id: number; total: number; items: Item[]; coupon?: string;.
What inference cannot know
Samples show what happened, not what is allowed. A status field that only ever said “active” is typed as string, not as a union of all statuses; IDs that look numeric may really be strings elsewhere. Treat the output as a strong first draft and refine it with what the API documentation promises.
Related tools
Tidy the input first with the JSON Formatter, convert existing interfaces with TypeScript to Zod, or generate the same models for a Go backend with JSON to Go and a Python service with JSON to Pydantic.
Checked against the current version of the JSON to TypeScript & Zod on .

