JSON Schema to TypeScript
About 1 minTC-Medium
JSON Schema to TypeScript
Problem
Implement JSONSchema2TS which converts a JSON Schema type into a TypeScript type.
type A = JSONSchema2TS<{ type: 'string' }> // string
type B = JSONSchema2TS<{ type: 'number' }> // number
type C = JSONSchema2TS<{ type: 'boolean' }> // boolean
type D = JSONSchema2TS<{ type: 'null' }> // null
type E = JSONSchema2TS<{
type: 'object'
properties: {
name: { type: 'string' }
age: { type: 'number' }
}
required: ['name']
}>
// { name: string; age?: number }
type F = JSONSchema2TS<{
type: 'array'
items: { type: 'string' }
}> // string[]Solution
type JSONSchema2TS<T> =
T extends { type: 'string' }
? string
: T extends { type: 'number' }
? number
: T extends { type: 'boolean' }
? boolean
: T extends { type: 'null' }
? null
: T extends { type: 'array'; items: infer Items }
? JSONSchema2TS<Items>[]
: T extends { type: 'object'; properties: infer Props; required: infer Req extends string[] }
? {
[K in keyof Props as K extends Req[number] ? K : never]: JSONSchema2TS<Props[K]>
} & {
[K in keyof Props as K extends Req[number] ? never : K]?: JSONSchema2TS<Props[K]>
}
: T extends { type: 'object'; properties: infer Props }
? { [K in keyof Props]?: JSONSchema2TS<Props[K]> }
: T extends { type: 'object' }
? Record<string, unknown>
: neverHow it works:
- Match scalar types (
string,number,boolean,null) directly. - For arrays, recurse on
items. - For objects with
propertiesandrequired, split keys into required (no?) and optional (with?) using two mapped types intersected together. - If no
requiredis present, all properties are optional. - An object with no
propertiesmaps toRecord<string, unknown>.
Key Takeaways
- Splitting required vs optional properties requires two separate mapped types (one for each set) combined with
&. K extends Req[number]tests membership in therequiredarray union.- Recursive schema resolution mirrors how JSON Schema itself is recursive.
