JSON Schema to TypeScript and Pydantic: Generate Types
A JSON Schema can generate the types your code uses, so the contract and the code cannot drift apart. Here is the output of two common generators, tested on one schema.
You can generate TypeScript types and Python models from a JSON Schema. The JSON Schema Generator infers a draft-07 schema from a sample document, and its page lists what to tighten before relying on it. Once the schema is right, it can do more than validate: it can generate the types your code uses, so the schema and the code describe the same thing.
This guide runs one order schema through two common generators, one for TypeScript and one for Python, and shows how a single schema keyword changes the output of both.
The schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Order",
"type": "object",
"properties": {
"id": { "type": "string" },
"status": { "type": "string", "enum": ["paid", "shipped", "refunded"] },
"total": { "type": "number" },
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"sku": { "type": "string" },
"qty": { "type": "integer", "minimum": 1 }
},
"required": ["sku", "qty"]
}
},
"coupon": { "type": ["string", "null"] }
},
"required": ["id", "status", "total", "items"]
}JSON Schema to TypeScript types
npm install --save-dev json-schema-to-typescript
npx json2ts -i order.schema.json -o order.d.tsexport interface Order {
id: string;
status: "paid" | "shipped" | "refunded";
total: number;
items: {
sku: string;
qty: number;
[k: string]: unknown;
}[];
coupon?: string | null;
[k: string]: unknown;
}Most of it maps directly. enum becomes a union of string literals, a field not listed in required becomes optional, and ["string", "null"] becomes string | null. Two things do not carry over: integer and minimum: 1 both become plain number, because TypeScript has no type for them. Only a validator enforces those rules at run time.
The keyword that changes the output
Note the [k: string]: unknown lines. JSON Schema allows extra properties unless told otherwise, so the generator has to allow any other key, and a typo such as order.totl then type-checks. Add "additionalProperties": false to the order and to the item schema, and the index signatures disappear:
export interface Order {
id: string;
status: "paid" | "shipped" | "refunded";
total: number;
items: {
sku: string;
qty: number;
}[];
coupon?: string | null;
}The same keyword makes validators reject unknown fields, so decide it deliberately: strict for data you produce, more open for data from systems that may add fields later.
JSON Schema to Pydantic models
pip install datamodel-code-generator
datamodel-codegen --input order.schema.json --input-file-type jsonschema \
--output-model-type pydantic_v2.BaseModel --output order_model.pyclass Status(Enum):
paid = 'paid'
shipped = 'shipped'
refunded = 'refunded'
class Item(BaseModel):
model_config = ConfigDict(extra='forbid')
sku: str
qty: conint(ge=1)
class Order(BaseModel):
model_config = ConfigDict(extra='forbid')
id: str
status: Status
total: float
items: list[Item]
coupon: str | None = NoneUnlike the TypeScript types, the Pydantic model also enforces the rules when it parses data. Given a status of lost, a quantity of 0 and an extra field, Order.model_validate reported all three problems: the status must be one of the enum values, the quantity must be greater than or equal to 1, and extra inputs are not permitted.
Keeping the code in step with the schema
Generated files go stale the moment someone edits the schema and forgets to regenerate. Treat the schema as the source, commit the generated files, and let CI check that they match:
npx json2ts -i order.schema.json -o src/types/order.d.ts
git diff --exit-code src/types/order.d.tsgit diff --exit-code fails the job when regeneration changed anything, so a schema change without the matching code change cannot be merged. Never edit the generated file by hand; change the schema and regenerate.
Related tools
Validate JSON against a JSON Schema using AJV.
Validate JSON syntax and pinpoint the exact line and column of any error.
Pretty-print JSON with configurable indentation and instant validation.
Turn JSON into clean, readable YAML for configs, pipelines and manifests.
Related guides
Checking a request body against a JSON Schema replaces dozens of hand-written if statements. Here is a tested setup for Node and Python, and a 400 response that tells the client exactly what to fix.
The same file opens cleanly in VS Code and is rejected by npm. The difference is which of three JSON dialects each tool reads.
Two formatters can disagree about the same JSON file. Here is how a team picks one, applies it in every editor and before every commit, and makes CI enforce it.
YAML is easier to read and easier to get wrong. Here is what each format gives you for configuration, the mistakes YAML lets through, and a rule for choosing.