1 /* eslint-disable @typescript-eslint/no-empty-interface */
2 type StrictNullChecksWrapper<Name extends string, Type> = undefined extends null
3 ? `strictNullChecks must be true in tsconfig to use ${Name}`
6 type UnionToIntersection<U> = (U extends any ? (_: U) => void : never) extends (_: infer I) => void
10 export type SomeJSONSchema = UncheckedJSONSchemaType<Known, true>
12 type UncheckedPartialSchema<T> = Partial<UncheckedJSONSchemaType<T, true>>
14 export type PartialSchema<T> = StrictNullChecksWrapper<"PartialSchema", UncheckedPartialSchema<T>>
16 type JSONType<T extends string, IsPartial extends boolean> = IsPartial extends true
20 interface NumberKeywords {
23 exclusiveMinimum?: number
24 exclusiveMaximum?: number
29 interface StringKeywords {
36 type UncheckedJSONSchemaType<T, IsPartial extends boolean> = (
37 | // these two unions allow arbitrary unions of types
39 anyOf: readonly UncheckedJSONSchemaType<T, IsPartial>[]
42 oneOf: readonly UncheckedJSONSchemaType<T, IsPartial>[]
44 // this union allows for { type: (primitive)[] } style schemas
46 type: readonly (T extends number
47 ? JSONType<"number" | "integer", IsPartial>
49 ? JSONType<"string", IsPartial>
51 ? JSONType<"boolean", IsPartial>
53 } & UnionToIntersection<
59 ? // eslint-disable-next-line @typescript-eslint/ban-types
63 // this covers "normal" types; it's last so typescript looks to it first for errors
66 type: JSONType<"number" | "integer", IsPartial>
70 type: JSONType<"string", IsPartial>
74 type: JSONType<"boolean", IsPartial>
76 : T extends readonly [any, ...any[]]
78 // JSON AnySchema for tuple
79 type: JSONType<"array", IsPartial>
81 readonly [K in keyof T]-?: UncheckedJSONSchemaType<T[K], false> & Nullable<T[K]>
82 } & {length: T["length"]}
84 } & ({maxItems: T["length"]} | {additionalItems: false})
85 : T extends readonly any[]
87 type: JSONType<"array", IsPartial>
88 items: UncheckedJSONSchemaType<T[0], false>
89 contains?: UncheckedPartialSchema<T[0]>
95 additionalItems?: never
97 : T extends Record<string, any>
99 // JSON AnySchema for records and dictionaries
100 // "required" is not optional because it is often forgotten
101 // "properties" are optional for more concise dictionary schemas
102 // "patternProperties" and can be only used with interfaces that have string index
103 type: JSONType<"object", IsPartial>
104 additionalProperties?: boolean | UncheckedJSONSchemaType<T[string], false>
105 unevaluatedProperties?: boolean | UncheckedJSONSchemaType<T[string], false>
106 properties?: IsPartial extends true
107 ? Partial<UncheckedPropertiesSchema<T>>
108 : UncheckedPropertiesSchema<T>
109 patternProperties?: Record<string, UncheckedJSONSchemaType<T[string], false>>
110 propertyNames?: Omit<UncheckedJSONSchemaType<string, false>, "type"> & {type?: "string"}
111 dependencies?: {[K in keyof T]?: Readonly<(keyof T)[]> | UncheckedPartialSchema<T>}
112 dependentRequired?: {[K in keyof T]?: Readonly<(keyof T)[]>}
113 dependentSchemas?: {[K in keyof T]?: UncheckedPartialSchema<T>}
114 minProperties?: number
115 maxProperties?: number
116 } & (// "required" type does not guarantee that all required properties
117 // are listed it only asserts that optional cannot be listed.
118 // "required" is not necessary if it's a non-partial type with no required keys
119 IsPartial extends true
120 ? {required: Readonly<(keyof T)[]>}
121 : [UncheckedRequiredMembers<T>] extends [never]
122 ? {required?: Readonly<UncheckedRequiredMembers<T>[]>}
123 : {required: Readonly<UncheckedRequiredMembers<T>[]>})
126 type: JSONType<"null", IsPartial>
130 allOf?: Readonly<UncheckedPartialSchema<T>[]>
131 anyOf?: Readonly<UncheckedPartialSchema<T>[]>
132 oneOf?: Readonly<UncheckedPartialSchema<T>[]>
133 if?: UncheckedPartialSchema<T>
134 then?: UncheckedPartialSchema<T>
135 else?: UncheckedPartialSchema<T>
136 not?: UncheckedPartialSchema<T>
139 [keyword: string]: any
142 $defs?: Record<string, UncheckedJSONSchemaType<Known, true>>
143 definitions?: Record<string, UncheckedJSONSchemaType<Known, true>>
146 export type JSONSchemaType<T> = StrictNullChecksWrapper<
148 UncheckedJSONSchemaType<T, false>
152 | {[key: string]: Known}
153 | [Known, ...Known[]]
160 type UncheckedPropertiesSchema<T> = {
161 [K in keyof T]-?: (UncheckedJSONSchemaType<T[K], false> & Nullable<T[K]>) | {$ref: string}
164 export type PropertiesSchema<T> = StrictNullChecksWrapper<
166 UncheckedPropertiesSchema<T>
169 type UncheckedRequiredMembers<T> = {
170 [K in keyof T]-?: undefined extends T[K] ? never : K
173 export type RequiredMembers<T> = StrictNullChecksWrapper<
175 UncheckedRequiredMembers<T>
178 type Nullable<T> = undefined extends T
181 const?: null // any non-null value would fail `const: null`, `null` would fail any other value in const
182 enum?: Readonly<(T | null)[]> // `null` must be explicitly included in "enum" for `null` to pass