Generate TypeScript types from JSON Schema
The JSON Schema → TypeScript converter turns a JSON Schema object into clean,
idiomatic TypeScript interface definitions. It is built for the LLM era, where
function-calling tool schemas and structured-output formats are expressed in JSON
Schema — generating matching interfaces lets you parse tool arguments and model
responses with full type safety.
How it works
The generator walks the schema recursively. Object types become interfaces;
properties not in the required array become optional (?). Arrays map to
T[], string enums map to string-literal unions, and $ref pointers resolve
against definitions or $defs. anyOf and oneOf render as union types.
Nested anonymous objects get auto-named child interfaces so the output stays
readable. Unknown or unsupported constructs degrade gracefully to unknown.
Mapping rules at a glance
| JSON Schema | TypeScript output |
|---|---|
{"type": "string"} | string |
{"type": "number"} | number |
{"type": "integer"} | number |
{"type": "boolean"} | boolean |
{"type": "null"} | null |
{"type": "array", "items": {...}} | T[] |
{"enum": ["a", "b"]} | "a" | "b" |
{"anyOf": [...]} | union type |
{"$ref": "#/$defs/Foo"} | resolved to Foo interface |
Properties absent from required | fieldName? (optional) |
A practical worked example
Take this function-calling schema for a weather tool:
{
"type": "object",
"properties": {
"location": { "type": "string", "description": "City name" },
"units": { "enum": ["celsius", "fahrenheit"] }
},
"required": ["location"]
}
The generator produces:
interface Root {
location: string;
units?: "celsius" | "fahrenheit";
}
location is non-optional (it is in required). units becomes a string-literal union from the enum values, and the trailing ? marks it optional. You can now type the argument object passed to your weather function handler:
function handleWeather(args: Root) {
const unit = args.units ?? "celsius";
// TypeScript knows units is "celsius" | "fahrenheit" | undefined
}
Tips and notes
If your schema uses $ref, keep the referenced definitions under $defs or
definitions so they resolve. For LLM tool calling, generate the interface for
your function’s parameters schema and type the arguments you receive from the
model. When a field can be several shapes, oneOf produces a discriminated-union
candidate you can refine. The output is plain text — copy it directly into your
project.
After generating, rename Root to something descriptive and review any unknown
fields — those indicate schema constructs the generator could not map, which you
should type by hand.