Skip to content

JSON Schema to TypeScript Definitions — Numio

Compiles a JSON Schema into TypeScript interfaces with json-schema-to-typescript. Properties not listed in "required" become optional, and objects get an index signature unless additionalProperties is false.

Your API publishes JSON Schema files and you want matching interfaces for the client code that consumes them.

JSON Schema

TypeScript

When to use it

  • Your API publishes JSON Schema files and you want matching interfaces for the client code that consumes them.
  • You keep config files validated by a schema and want type checking where the config is loaded.

How to use

  1. Paste a JSON Schema into the JSON Schema panel. A "title" sets the interface name; without one the root is named MySchema.
  2. Conversion runs in the browser as you type; the page has no settings and adds no banner comment.
  3. Copy the interfaces from the TypeScript panel. The page formats them with Prettier, so they use two-space indentation and no semicolons.

JSON Schema

{
  "title": "Address",
  "type": "object",
  "properties": {
    "street": { "type": "string", "minLength": 1 },
    "zip": { "type": "string", "pattern": "^[0-9]{5}$" },
    "country": { "enum": ["US", "CA"], "default": "US" },
    "unit": { "type": ["integer", "null"] },
    "lines": { "type": "array", "items": { "type": "string" }, "maxItems": 3 },
    "geo": { "type": "object", "required": ["lat", "lng"],
      "properties": { "lat": { "type": "number" }, "lng": { "type": "number" } } }
  },
  "required": ["street", "zip"]
}

TypeScript interfaces

export interface Address {
  street: string
  zip: string
  country?: "US" | "CA"
  unit?: number | null
  lines?: [] | [string] | [string, string] | [string, string, string]
  geo?: {
    lat: number
    lng: number
    [k: string]: unknown
  }
  [k: string]: unknown
}

Details and limitations

Objects without "additionalProperties": false get [k: string]: unknown, so extra keys stay allowed in the type.

maxItems on an array is expanded into a union of tuples, as with "lines" in the example.

Local $ref entries such as #/definitions/Tag become separate exported interfaces.

The page runs the result through Prettier without semicolons, which also removes redundant parentheses around unions such as "US" | "CA".

FAQ

How are null values typed?

"type": ["integer", "null"] becomes (number | null). integer and number both map to number.

How do I get rid of [k: string]: unknown?

Add "additionalProperties": false to each object schema; the index signature is then omitted.

How is the root interface named?

From the schema's "title" converted to PascalCase ("Example Schema" becomes ExampleSchema). With no title the name is MySchema.

Is the schema sent to a server?

No. The json-schema-to-typescript compile function runs in the browser on this page.

Specifications and references