JSON to TypeScript Interface Generator Guide

What is a JSON to TypeScript generator?

A JSON to TypeScript generator takes sample JSON and turns it into TypeScript definitions. In practice, that usually means reading object keys, value types, nested arrays, and nested objects, then emitting interfaces or type aliases that match the observed structure.

This is useful any time you have data before you have types. You might be working from an API response in DevTools, a webhook example from vendor docs, a fixture file in tests/, or a blob copied from Postman. Instead of manually translating that payload into TypeScript, a json to typescript interface tool gives you a first draft in seconds.

The tradeoff is important: the output is inferred from examples, not guaranteed by a schema. A tool can tell you what this sample looks like. It cannot guarantee what every future payload will look like unless your sample actually covers those cases.

Because Toolzy.dev runs entirely in the browser, this json to typescript type generator keeps generation local. That's a practical advantage when you're working with internal payloads, debugging production-like data, or handling customer objects you do not want to paste into a hosted service.

How to use this tool

  1. Paste a JSON object or a non-empty array of objects into the input.
  2. Set a root name if you want something better than a generic Root.
  3. Generate the TypeScript output.
  4. Review the result for optional fields, unions, and naming.
  5. Copy the types into your project and refine them to match the real contract.

If you want higher-quality output, do not use the smallest possible sample. Use JSON that reflects the actual variety of your data. A sample like { "items": [] } is valid, but it does not tell the generator what belongs in items. A root array also needs actual object items, not primitives or an empty list.

Common use cases

Sample-based inference: what the generator can and cannot know

Sample-based inference is fast because it starts from real data, but it has blind spots. If the generator sees:

{
  "id": 42,
  "name": "Ada",
  "active": true
}

it can safely infer id: number, name: string, and active: boolean. What it cannot infer is whether id is an integer with business meaning, whether name can be null, or whether active is sometimes omitted in older API versions.

That means generated output should be treated as inferred structure, not a contract. If your backend already has an OpenAPI spec, JSON Schema, Zod schema, or shared server types, those should remain authoritative. Use json to ts generation as a bootstrap step, not a replacement for real contracts.

Arrays, nullable values, and optional fields

These three cases cause most of the manual cleanup.

Arrays

If the sample contains concrete items, array inference is straightforward:

{
  "tags": ["ts", "api"],
  "scores": [1, 2, 3]
}

becomes something close to tags: string[] and scores: number[].

If the array contains objects, the generator can infer the item shape and create a nested interface. If the array is empty, it has no evidence. That is why empty arrays often become unknown[], any[], or a placeholder type that you should tighten manually. Root arrays are only supported when every item is an object.

Mixed arrays are another special case. A payload like [1, "two", null] implies a union item type. TypeScript can express that as (number | string | null)[], but broad unions are often a signal that either the sample is noisy or the underlying contract is inconsistent.

Nullable values

JSON has a real null value, so any generator has to decide how to model it. If a field is always null in the sample, the safest inference may be field: null, which is technically correct but not very useful. If the sample set includes both strings and null, then field: string | null is the natural result.

This is one reason representative samples matter. A single object with "completedAt": null does not tell the generator whether that field is always null, temporarily null, or nullable until some lifecycle event completes.

Optional fields

Optionality requires comparison across objects. If one object has email and another does not, the tool can infer email?: string. If you only provide one object, the tool cannot distinguish between required and merely present.

When developers say a generated type is "too strict," this is usually why. The sample made all properties look required. The fix is either to provide multiple representative objects or to edit the result manually.

Supported property names

Most JSON object keys are fine, including keys with spaces or punctuation because the generator can quote them in TypeScript. Two cases are intentionally rejected because they do not round-trip safely through the bundled json-to-ts library:

If you hit either case, rename the key in the sample before generating.

Unions and inconsistent APIs

Union types are often a faithful reflection of messy inputs. If one payload gives you status: "ok" and another gives status: 200, a generator may emit status: string | number. That may be correct for the sample and still be a problem for your system design.

Use generated unions as a signal to inspect the source data. Sometimes the backend contract is genuinely polymorphic. Other times the sample is mixing old and new API versions, or mixing transport values with normalized values.

For example, this JSON:

[{ "result": { "kind": "user", "id": 1 } }, { "result": "not_found" }]

may push the generator toward a broad union around result. TypeScript can model that, but you may get cleaner application code by normalizing the payload at your boundary instead of spreading that union everywhere.

Root naming matters more than people think

Generated code often defaults to Root, RootObject, or similar placeholders. That is fine for a quick paste, but weak names spread confusion fast in real codebases.

Prefer names tied to the domain: StripeCheckoutSession, GithubPullRequest, WebhookDelivery, FeatureFlagResponse. A good root name tells the next developer where the type came from and what it represents. If the tool lets you set a root name, do it before generating. If not, rename the result immediately after copying it.

Interfaces vs type aliases

Most developers asking for a json to typescript interface want interface output because interfaces are familiar and extendable:

interface User {
  id: number;
  name: string;
}

But type aliases can be a better fit for unions, mapped types, tuples, and inline object combinations:

type Result = User | "not_found";

There is no universal winner. Interfaces work well for plain object models and declaration merging is occasionally useful. Type aliases are more flexible for advanced compositions. If your generated output is mostly nested objects, interfaces are fine. If the inferred shapes rely heavily on unions or non-object roots, type aliases may produce clearer code.

Generation limits and when manual review is required

Every generator has limits because JSON itself does not carry semantic intent.

That is why the generated output should be reviewed before it lands in src/types/ or gets published as part of a public SDK. The generator handles the repetitive translation work. You still provide the engineering judgment.

When to use this instead of schemas or codegen

Use JSON-based inference when you need speed and have concrete samples. It is ideal for exploration, prototyping, and one-off integration work.

Use schema-driven generation when you need repeatability. OpenAPI, GraphQL codegen, protobufs, JSON Schema, Zod, or server-shared TypeScript types are better when the contract needs to stay synchronized over time.

The two approaches are not mutually exclusive. Many teams start with generated types from a sample payload, then replace them later with schema-based types once the API stabilizes.

Troubleshooting

Why did the tool generate any[] or unknown[] for my array? — Your sample array was empty or too inconsistent to infer a stable item shape. Provide a representative non-empty array, then regenerate.

Why are all fields required? — The generator only saw one object shape, so every observed property looked required. Add multiple objects where some fields are missing, or make those properties optional by hand.

Why did I get a union like string | number | null? — Your sample data contains multiple value types for the same field. The output is reflecting that inconsistency. If the real API contract is narrower, tighten the type manually.

Can this know the difference between an integer ID and a floating-point value? — No. JSON only gives the tool a number literal, so TypeScript inference ends at number. Semantic distinctions still need manual review.

Should I trust generated types in production without edits? — No. Use them as a starting point. Generated types are inferred from sample JSON and should be reviewed against real API behavior or an authoritative schema.

Is my data uploaded anywhere? — No. On Toolzy.dev, generation runs in the browser, so the JSON stays local to your machine.