JSON to TypeScript Converter

Paste a JSON sample and instantly generate matching TypeScript interfaces, including nested types, array element types, and optional properties inferred from inconsistent object shapes. A free online tool from Staaarter, right in your browser.

Runs locallyUpdated 2026-07-18

Overview

Introduction

Hand-writing TypeScript interfaces for a large API response is tedious and error-prone. This tool infers interfaces directly from a real JSON sample, so the types you get actually match the data your code will receive.

It exists because keeping types in sync with an API by hand doesn't scale. A response with a dozen nested objects and optional fields takes real effort to model correctly, and it's easy to miss an optional property that just happens to be present in the one example you looked at. Generating from an actual payload removes that guesswork — the output is derived mechanically from the data rather than typed from memory.

What Is JSON to TypeScript Converter?

A JSON-to-TypeScript generator walks a JSON sample and produces one or more `interface` declarations that describe its shape: property names, primitive types, nested object types, and array element types.

Unlike a schema format, the output is TypeScript source you paste directly into a `.ts` file. There's no intermediate representation to consume at runtime, the generated interfaces exist purely for compile-time checking, which is exactly what you want when the only goal is catching a typo'd property name or a wrong assumption about a field's type before it ships.

How JSON to TypeScript Converter Works

For each object encountered, the generator creates a named interface using PascalCase derived from the property path. Arrays of objects have their element shapes merged, so any key missing from at least one array item becomes optional. Arrays of primitives become typed arrays, and arrays mixing primitive types become union arrays. Nested objects recursively generate their own named interfaces instead of being inlined, which keeps the output readable.

Because inference works from shape-merging rather than a fixed schema, an array with three items that each expose slightly different keys still produces a single, correct interface. The generator takes the union of all keys seen and marks anything not present in every item as optional with a `?`. It's the same reasoning a developer would apply manually, just applied consistently, without missing an item three levels deep in a large payload.

When To Use JSON to TypeScript Converter

Use it right after receiving a new API response you need to consume in a TypeScript project, when writing a mock or fixture that needs a matching type, or when documenting the shape of a JSON payload for teammates.

It's also a starting point rather than a final answer. Generate the interface from a representative sample, then rename the auto-derived PascalCase names and tighten any fields that deserve a string literal union instead of a bare `string`. That's still faster than starting from a blank file, even with some manual cleanup left over.

Features

Advantages

  • Saves significant time versus hand-writing interfaces for nested API responses.
  • Infers optional properties automatically from inconsistent sample data.
  • Produces named, reusable nested interfaces instead of a single deeply-inlined type.
  • Detects primitive union types in mixed arrays.

Limitations

  • Inference is based only on the sample you provide, so fields absent from your sample won't appear in the generated type.
  • Cannot infer string literal unions, enums, or branded types; string fields are always typed as `string`.
  • Does not generate JSDoc comments or validate the generated code against your project's lint rules.

TypeScript Interfaces vs. JSON Schema

TypeScript Interfaces vs. JSON Schema
TypeScript interfaces (this tool)JSON Schema
Gives compile-time autocomplete and type checksYesNo, needs a separate type-generation step
Validates data at runtimeNo, types disappear at compile timeYes, with a validator like Ajv
Consumed by OpenAPI and API gatewaysNo, needs a conversion stepYes
Best forType-safe TypeScript codeValidating incoming API payloads

Examples

Object with a nested array and a nested object

Input

{"id":1,"tags":["a","b"],"author":{"name":"Ada"}}

Output

interface Root {
  id: number;
  tags: string[];
  author: RootAuthor;
}

interface RootAuthor {
  name: string;
}

The top-level interface is declared first, with the nested "author" object referenced by its derived name RootAuthor. The RootAuthor interface itself is declared afterward. Nested objects always become their own named interface rather than being inlined.

Array of objects with inconsistent keys

Input

{"users":[{"id":1,"name":"Ada"},{"id":2,"name":"Bo","admin":true}]}

Output

interface Root {
  users: RootUsers[];
}

interface RootUsers {
  id: number;
  name: string;
  admin?: boolean;
}

"admin" appears in only the second array item, so the merged interface marks it optional with a ? instead of dropping it or requiring it on every item.

A null field

Input

{"id":1,"middleName":null}

Output

interface Root {
  id: number;
  middleName: null;
}

A null sample value is typed as the literal null, not string | null or unknown. The key is still required (no ?), since null is a value, not an absence.

Mixed-type array becomes a union

Input

{"values":[1,"two",3]}

Output

interface Root {
  values: (number | string)[];
}

When array elements aren't all the same primitive type, the generator produces a parenthesized union array type listing each distinct type once, in first-seen order.

Keys that aren't valid identifiers

Input

{"user-id":1,"2fa":true}

Output

interface Root {
  "user-id": number;
  "2fa": boolean;
}

Keys containing a hyphen or starting with a digit aren't valid bare TypeScript identifiers, so the generator emits them as quoted string-literal property names instead, which is still valid interface syntax.

Top-level array of objects (naming collision)

Input

[{"id":1,"name":"Ada"},{"id":2,"name":"Bo"}]

Output

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

type Root = Root[];

When the whole JSON document is an array of objects, the item interface is named directly after the root name, and a type Root = Root[] alias gets added for the array itself. Both declarations share the name "Root", which TypeScript rejects as a duplicate identifier, so you'll need to rename one of the two by hand before using this output. Renaming the root name field first doesn't avoid the collision, since both declarations always inherit whatever name you choose.

Invalid JSON input

Invalid input

{"a": 1,}

Parser error

SyntaxError: Expected double-quoted property name in JSON at position 8 (line 1 column 9)

The generator parses your input with JSON.parse() before doing any type inference, so a trailing comma or any other syntax error gets reported immediately as a parse error, in the exact same wording you'd get from the JSON Validator, rather than the generator attempting a partial or best-guess type.

Corrected version

{"a": 1}

Best Practices & Notes

Best Practices

  • Use a JSON sample that includes optional/nullable fields in at least one representative case so the generator can infer them correctly.
  • Rename generated interfaces to something more meaningful than the auto-derived PascalCase names before committing them.
  • Re-run generation whenever the upstream API shape changes rather than hand-patching stale types.
  • When the top-level JSON value is an array of objects, rename either the generated interface or the type alias by hand before compiling, since the tool always emits both under the same identifier.
  • Prefer a sample array with two or three items that differ slightly in shape over a single item, since a one-item array can't reveal which fields are ever actually optional.
  • Run the generated output through your project's own tsc or linter before committing it. The generator doesn't check the result against your existing type names or style rules.

Developer Notes

Interface names get deduplicated by name. If two different branches of the JSON produce the same derived interface name, the second declaration is treated as identical for output purposes, and only the first one generated is kept, even if the underlying shapes actually differ. For genuinely different shapes that happen to collide, rename the root type before generating so the derived names diverge. Property names are validated against the same bare-identifier grammar TypeScript itself requires for unquoted object keys. Anything that fails that check, a hyphenated key, a key starting with a digit, gets emitted as a quoted string-literal property instead of a bare identifier, which keeps the output valid without needing to rename the source data. One edge case worth knowing about ahead of time: when the top-level JSON value is itself an array of objects, the generator names the item interface directly after the root name and also emits a type Root = Root[] alias, so both declarations end up sharing the same identifier. TypeScript rejects that as a duplicate identifier, and changing the root name field doesn't avoid it, since both declarations always inherit whatever name is chosen. The output needs a manual rename of one of the two before it'll compile.

JSON to TypeScript Converter Use Cases

  • Typing a new REST or GraphQL API response in a TypeScript client
  • Generating a starting type for a JSON fixture in tests
  • Documenting a webhook payload shape for other engineers
  • Bootstrapping types for a JSON config file
  • Generating a quick reference type while reviewing a pull request that changes an API response shape
  • Producing types for a JSON payload from an internal tool or admin API that has no OpenAPI spec of its own

Common Mistakes

  • Generating types from a single sample and assuming every field is always present. Use multiple representative samples when possible.
  • Not renaming the generic derived interface names before shipping the code.
  • Expecting numeric string fields (like "42") to be typed as `number`. They remain `string` since that's their actual JSON type.
  • Feeding the generator a top-level array without expecting the interface/type-alias naming collision. The generated code needs a manual rename before it'll compile.
  • Assuming a field typed as `null` in the output means "optional". The generator only marks a key optional when it's missing from at least one array item, not when its present value happens to be null.

Tips

  • If your API has optional fields, include a JSON sample where at least one object omits that field so it's correctly marked optional.
  • Combine with the JSON Schema Generator when you need runtime validation in addition to compile-time types.
  • If the top-level JSON value is an array, rename either the interface or the type alias in the generated output before pasting it into your project, since both declarations share a name and TypeScript will otherwise reject them as duplicates.
  • Paste a representative sample that includes any hyphenated or numeric-looking keys your API actually uses, so you can see upfront which property names will need quoted syntax in the interface.

References

Frequently Asked Questions