JSON Schema to TypeScript: Complete Code Generation Guide

When your API has 40+ endpoints, each with its own request and response schema, writing TypeScript interfaces by hand is not just tedious — it is a source of bugs. One missed field, one wrong type, and your compile-time safety is gone.

I automated this with JSON Schema to TypeScript generation. Here is exactly how it works and the edge cases that still require manual intervention.

The Basic Mapping

{
  "type": "object",
  "properties": {
    "id": { "type": "integer" },
    "name": { "type": "string" },
    "email": { "type": "string", "format": "email" },
    "age": { "type": "integer", "minimum": 0 },
    "isActive": { "type": "boolean" },
    "tags": { "type": "array", "items": { "type": "string" } },
    "metadata": { "type": "object" }
  },
  "required": ["id", "name", "email"]
}

Generates:

interface User {
  id: number;
  name: string;
  email: string;
  age?: number;      // Optional because not in "required"
  isActive?: boolean;
  tags?: string[];
  metadata?: Record<string, unknown>;
}

The mapping rules:

JSON Schema TypeTypeScript Type
stringstring
integernumber
numbernumber
booleanboolean
nullnull
arrayArray<T>
object (with properties)Interface
object (no properties)Record<string, unknown>

Handling $ref References

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "user": { "$ref": "#/$defs/User" },
    "address": { "$ref": "#/$defs/Address" }
  },
  "$defs": {
    "User": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "email": { "type": "string" }
      }
    },
    "Address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" }
      }
    }
  }
}

Generates:

interface User {
  name: string;
  email: string;
}

interface Address {
  street: string;
  city: string;
}

interface RootObject {
  user: User;
  address: Address;
}

On Stack Overflow, a question about handling $ref in code generation has 18,000 views. The tricky part is resolving circular references, which not all generators handle.

Enum and Union Types

{
  "type": "object",
  "properties": {
    "status": {
      "type": "string",
      "enum": ["active", "inactive", "suspended"]
    },
    "role": {
      "anyOf": [
        { "type": "string" },
        { "type": "null" }
      ]
    }
  }
}

Generates:

type Status = "active" | "inactive" | "suspended";

interface User {
  status: Status;
  role: string | null;
}

The Edge Case That Broke Our Client

When a schema uses additionalProperties with a typed value:

{
  "type": "object",
  "properties": {
    "metadata": {
      "type": "object",
      "additionalProperties": { "type": "string" }
    }
  }
}

Most generators output { [key: string]: string } or Record<string, string>. But our schema had:

{
  "additionalProperties": {
    "anyOf": [
      { "type": "string" },
      { "type": "integer" },
      { "type": "boolean" }
    ]
  }
}

The generated Record<string, string | number | boolean> clashed with how our API actually sent the data (nested objects for some values). The fix was to add unevaluatedProperties: false to the schema and explicitly define every property.

Tools for Generation

ToolApproachBest For
json-schema-to-ts (npm)Type-level (no code gen)Direct schema import
quicktypeFull code generationMultiple languages
openapi-typescriptOpenAPI → TypeScriptFull API clients
json-schema-codegenTemplate-basedCustom output formats

Related Searches

  • json schema to typescript
  • generate typescript from json schema
  • json schema typescript codegen
  • json schema to typescript interface
  • json schema ref typescript
  • json schema enum typescript
  • json schema additionalproperties typescript
  • json schema code generation comparison
  • openapi typescript generator
  • json schema to typescript quicktype

Frequently Asked Questions

Can I generate TypeScript interfaces directly from JSON Schema?

Yes. Tools like json-schema-to-ts, quicktype, and openapi-typescript generate TypeScript interfaces from JSON Schema or OpenAPI specs. The generated types provide compile-time validation for API responses and request bodies.

How does code generation handle $ref and circular references?

$ref references are converted to TypeScript interface references. Circular references (where Schema A references Schema B which references Schema A) are handled by generating separate interfaces and using optional types or type aliases to break the cycle.

What about nullable properties?

JSON Schema represents nullable as { "anyOf": [{ "type": "string" }, { "type": "null" }] }. This generates as string | null in TypeScript. Properties not in the schema's required array generate as optional (?).

Should I check generated types into version control?

Yes. Generated types should be committed alongside your schema files. Include the generation command in your build script so types are regenerated when the schema changes. This ensures type safety is always in sync.

Final Thoughts

JSON Schema to TypeScript generation is one of the highest-ROI automation investments you can make for a TypeScript API client. It eliminates a class of bugs (field name typos, wrong types, missing fields) that are otherwise undetectable until runtime.