genever
Generate TypeScript types from a JSON Schema file, or the schemas of an OpenAPI document, with strict checks of the schema itself.
Point it at a schema:
json
{
"type": "object",
"properties": {
"id": { "type": "string", "pattern": "^usr_" },
"point": {
"type": "array",
"prefixItems": [{ "type": "number" }, { "type": "number" }],
"items": false,
"minItems": 2
},
"tags": { "type": "array", "items": { "type": "string" }, "minItems": 1 }
},
"required": ["id"]
}Run npx genever user.json --name User, and it writes user.ts:
ts
export type User = {
id: `usr_${string}`;
point?: [number, number];
tags?: [string, ...string[]];
};Commit the result, and run genever --ci in CI to fail when it is out of date.
Features
- Types that match the schema: tuples,
oneOfunions that narrow,^prefixpatterns as template literals, closedpatternProperties, recursive$defs,if/then/elseandminItemsall become precise types, notanyorunknown[]. See Type mapping. - Round-trips Juniper: a schema built with Juniper, serialized and read back, gives the same type Juniper inferred. See Juniper round trip.
- Strict by default: unknown keywords, keywords that don't apply to the type, undeclared
requiredproperties and contradictions likeminLengthovermaxLengthfail generation. Without strict mode, types follow exactly what a validator accepts. See Strict mode. - One file from many:
$refs to other files and URLs are loaded and generated into the same output, with$idand$anchorresolved as the spec says. See References to other files. - OpenAPI documents: every
components.schemasentry of an OpenAPI 3.0 or 3.1 document becomes a type, and its operations becomePathsandOperationstypes, shaped like openapi-typescript's. See OpenAPI documents. - Types only: the output is plain TypeScript, with no runtime dependency.
Compared to
Each tool was given the same schema, built with Juniper, and its type checked against 21 valid and invalid values. genever passed all 21; the others passed 12 to 16. See Why genever.
- json-schema-to-typescript turns 2020-12 tuples into
never[], types everypatternasstring, and opens objects withpatternPropertiesto any key. - quicktype merges
oneOfobjects into one type with optional fields. - json-schema-to-zod generates a validator, but every
$refbecomesz.any(). - json-schema-to-ts and TypeBox infer types inside TypeScript, so the schema has to be pasted in
as const. An imported.jsonfile widens tounknown.