induwara.lk
induwara.lkDeveloper · Utility

JSON to TypeScript Converter

Paste a JSON value and get clean TypeScript interfaces or type aliases in one pass — nested objects extracted into named types, array elements merged, null and missing keys turned into optional or nullable members. Runs entirely in your browser; nothing is uploaded.

By Induwara AshinsanaUpdated Jun 23, 2026
JSON to TypeScript
Runs in your browser
Output style
Array elements
Null handling

227 characters. Paste an API response, then tweak the options above.

Status
Valid JSON
Parsed per RFC 8259
Types generated
3
3 interfaces: RootItems, RootCustomer, Root
Accepts input
Verified
The original JSON type-checks against the output.
Input size
227
characters parsed

How it works

This is a deterministic source-to-source transformation, not a guess. The JSON is parsed once with JSON.parse following RFC 8259, which defines the six JSON value types — object, array, string, number, boolean, and null. A single recursive pass then infers a TypeScript type for every node, using the rules from the TypeScript Handbook.

  1. Primitives. JSON string string, number → number (TypeScript has no int/float split, so every JSON number is number), true/false boolean, and nullnull.
  2. Objects become named types. Each object is emitted as an interface (or a type alias). The name is the parent name plus the PascalCased key — a customer object under Root becomes RootCustomer — so nested types never collide.
  3. Arrays become element types. Under the Union strategy every element is inferred and the results are merged: object fields are unioned, and a key present in only some elements is marked optional. An empty array has nothing to infer from, so it becomes unknown[] — never any[]. The First-element strategy instead infers from index 0 only, which is faster for lists you know are uniform.
  4. Optional and nullable. A key whose value is null is handled by your Null handling setting: key?: T (optional), key: T | null (nullable), or key?: T | null(both). Keys missing from some merged siblings are always optional, per the Handbook's optional-property rule.
  5. Dedup, ordering, and safety. Structurally identical objects are emitted once and reused. Declarations print children before parents so the file compiles top to bottom. Keys that are not valid identifiers are quoted ("first-name": string), and reserved root names are rejected before generation.

Because the rules are fixed, identical input and identical settings always produce byte-identical output. As a cross-check, the converter runs a structural assignability test — it confirms your original JSON value satisfies the types it just generated — and shows the result as the Accepts inputbadge. For a shape inferred straight from your value under the Union strategy this is always green; with First-element it may warn that later array elements don't match.

Worked examples

Nested object + a nullable field

interface · union · optional+nullable · export on

Input JSON

{ "order_id": "ORD-1042", "amount": 4500,
  "paid": true, "paid_at": null,
  "customer": { "name": "Nimal", "loyalty_id": 88 } }

TypeScript output

export interface RootCustomer {
  name: string;
  loyalty_id: number;
}
export interface Root {
  order_id: string;
  amount: number;
  paid: boolean;
  paid_at?: null;
  customer: RootCustomer;
}
  1. order_id → string, amount/loyalty_id → number, paid → boolean (step 1).
  2. customer is extracted into RootCustomer and referenced (step 2).
  3. paid_at is only ever null, so no concrete type exists: it is emitted as paid_at?: null (step 4). Give it a real value elsewhere and it would become string | null.

Array of objects with a missing key

interface · union · export off

Input JSON

{ "items": [
    { "sku": "A1", "qty": 2, "gift": true },
    { "sku": "B7", "qty": 1 }
] }

TypeScript output

interface RootItems {
  sku: string;
  qty: number;
  gift?: boolean;
}
interface Root {
  items: RootItems[];
}
  1. The two array elements are merged into one element type, RootItems (step 3).
  2. gift appears in the first element but not the second, so the merge marks it optional: gift?: boolean (step 4).
  3. items is typed as RootItems[].

Mixed primitive array + empty array

interface · union · export off

Input JSON

{ "vals": [1, "a", true], "tags": [] }

TypeScript output

interface Root {
  vals: (number | string | boolean)[];
  tags: unknown[];
}
  1. vals holds three different primitive types, so the element type is the deduplicated union (number | string | boolean), parenthesised before [].
  2. tags is empty — there is no element to infer — so it falls back to unknown[] rather than any[] (step 3).

Frequently asked questions

Sources & references

The type-mapping rules on this page were last cross-checked against the RFC 8259 value grammar and the TypeScript Handbook on 2026-06-23. The converter is deterministic, so its output can be reproduced exactly from the same input and settings.

Related tools

Rate this tool
Be the first to rate

Comments & feedback

Spotted a bug or want an improvement? Tell us — our team reviews every comment, and good ideas get built. Comments are public and anonymous.

Found a JSON shape that converts wrong, or want a feature like JSON Schema input?

Email me at [email protected] — most fixes ship within 24 hours.