JSON Schema to TypeScript

Convert a JSON Schema (draft-07) into TypeScript interfaces and type aliases — properties, required, enums, unions, $refs and nested objects. No upload.

JSON Schema

How it works

About JSON Schema to TypeScript

API contracts, config files and data fixtures are increasingly described with JSON Schema — but consuming that schema in TypeScript usually means either hand-writing the interfaces or pulling in a heavy build-time plugin. This tool does the translation in one pass: object schemas become interfaces, everything else collapses to primitive or union types, and local $defs/definitions are emitted as their own named declarations so the output stays readable.

The generated code is plain TypeScript — no dependencies, no generics machinery — so you can paste it into a .d.ts file or an existing source file and start using it immediately. The strict-mode toggle matches the two common conventions (all-optional by default vs. required-only-non-optional), and the prefix control avoids name collisions when you generate types for several schemas into the same file.

The draft-07 to TypeScript mapping

`object` becomes an interface, everything else becomes a type alias or an inline type. `string` maps to `string`, `boolean` to `boolean`, `null` to `null`. `integer` and `number` both map to `number` — TypeScript has one numeric type, so an integer constraint is not representable and `1.5` would type-check against an `integer` field. `array` with one `items` schema becomes `T[]`, and with an array of schemas a tuple `[A, B]`. An `enum` becomes a union of literal types.

Nullability comes from two places. A `type` array containing `null` produces `T | null`, with the null branch filtered out and re-appended. OpenAPI's `nullable: true` is honoured too. Draft-07 has no `nullable` keyword of its own, which is why the `type` array form is the portable one — a schema using a vendor extension like `x-nullable` is not recognised, and the field comes out non-nullable.

How $ref resolution stays finite

Only local pointers are followed, resolved by walking the parsed document: `#/$defs/Address` and `#/definitions/Address` both work, each segment percent-decoded first. Remote refs are not fetched. Recursion terminates because of ordering: an object schema's name is registered in a cache keyed on the schema object itself before its properties are walked, so a self-referential tree emits the interface's own name instead of descending again. A depth counter backstops anything that slips past, returning `any` past sixty levels.

Naming is handled rather than hoped for: the prefix is prepended to the root name and to every ref-derived name, characters outside `[A-Za-z0-9_$]` are stripped, a leading digit gets an `S`, and a collision appends an incrementing `2`, `3`. Inline nested objects are not prefixed — they are named by parent name plus capitalised property name, inheriting their parent's identity.

What the toggles change, and what the mapping loses

Strict mode is on by default: `required` members are emitted without a question mark and everything else stays optional, so the generated interface matches the schema's contract rather than quietly widening it. Turn it off to make every property optional — useful when a required field can still be missing off the wire, but the resulting type no longer describes what the schema guarantees.

Some schema information has no TypeScript counterpart and is dropped: `format`, `pattern`, `minimum`, `maxLength` and their siblings do not affect the emitted type, so an `email` field is just `string`. Several keywords are not implemented at all, and a schema relying on them will not error — it quietly produces something weaker than you wrote. `allOf` is the important omission, because intersection is the standard way to compose a base object with an extension, and an unhandled `allOf` yields a type that does not constrain what it should.

One combination produces code that does not compile. An `additionalProperties` schema emits `[key: string]: T`, and TypeScript then requires every named property to be assignable to `T` — so `name?: string` alongside `additionalProperties: { type: 'number' }` is an error, not a warning. `additionalProperties: false` is accepted and ignored. When a schema mixes declared properties with a typed index signature, check whether the types actually unify before committing the output.

Frequently Asked Questions

How do I convert JSON Schema to TypeScript?
Paste a JSON Schema document into the input and click Convert. The tool maps each schema type to the closest TypeScript equivalent: string → string, integer → number, boolean → boolean, object → interface, array → T[], and enum → union type.
Are all JSON Schema keywords supported?
Core keywords are supported: type, required, properties, patternProperties, additionalProperties, enum, const, format, minimum, maximum, minLength, maxLength, pattern, $ref, allOf, anyOf, oneOf, and if/then/else.
Is my data sent to a server?
No. Every tool on jsonversal runs entirely in your browser using the Web Crypto API, File API, and Clipboard API. Nothing is ever uploaded — not even the JSON you paste in.
Do I need an account or API key?
No signup, no email, no API key. All tools are free to use with no signup required.
Can I use these tools offline?
Yes. Once the page loads, all tools work offline. There are no external API calls or CDN dependencies at runtime.
🔒
Your data never leaves your device

All processing happens in your browser. No uploads, no tracking, no servers. Your API keys, configs, and private payloads stay private — 100% client-side.

esc
↑↓ navigate ↵ open esc close