-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
88 lines (73 loc) · 2.69 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/**
* Any valid JSON value.
*/
export type Value = null | number | string | boolean | readonly Value[] | object;
/**
* Any schema.
*/
export type Schema = object;
type SConst<T extends Value> = Readonly<{ const: T }>;
type SEnum<T extends Value> = Readonly<{ enum: readonly T[] }>;
type SNull = Readonly<{ type: "null" }>;
type SNumber = Readonly<{ type: "number" }>;
type SInteger = Readonly<{ type: "integer" }>;
type SString = Readonly<{ type: "string" }>;
type SBoolean = Readonly<{ type: "boolean" }>;
type SArray<I extends Schema, A extends Schema | boolean | undefined> = Readonly<{
type: "array";
items?: I | readonly I[];
additionalItems?: A;
}>;
type SObject<
P extends Readonly<{ [K in string]?: Schema }>,
R extends string,
A extends Schema | boolean | undefined,
> = Readonly<{
type: "object";
properties?: P;
required?: readonly R[];
additionalProperties?: A;
}>;
type SOneOf<S extends Schema> = Readonly<{ oneOf: readonly S[] }>;
type SAllOf<S extends Schema> = Readonly<{ allOf: readonly S[] }>;
/**
* Derives the type of data that the given JSON schema describes.
*/
export type TypeOfSchema<S extends Schema> = TypeOfSchemaInternal<S>;
type TypeOfSchemaInternal<S extends Schema | undefined> =
S extends SOneOf<infer S> ? TypeOfSOneOf<S>
: S extends SAllOf<infer S> ? TypeOfSAllOf<S>
: TypeOfSchemaInternalSub<S>;
type TypeOfSOneOf<S extends Schema> = TypeOfSchemaInternalSub<S>;
type TypeOfSAllOf<S extends Schema> = UnionToIntersection<TypeOfSchemaInternalSub<S>>;
type TypeOfSchemaInternalSub<S extends Schema | undefined> =
S extends SConst<infer T> ? T
: S extends SEnum<infer T> ? T
: S extends SNull ? null
: S extends SNumber ? number
: S extends SInteger ? number
: S extends SString ? string
: S extends SBoolean ? boolean
: S extends SArray<infer I, infer A> ? TypeOfSArray<I, A>
: S extends SObject<infer P, infer R, infer A> ? TypeOfSObject<P, R, A>
: Value;
type TypeOfSArray<I extends Schema, A extends Schema | boolean | undefined> = Array<
| TypeOfSchemaInternal<I>
| ([A] extends [Schema] ? TypeOfSchemaInternal<A>
: [A] extends [true] ? Value
: never)
>;
type TypeOfSObject<
P extends Readonly<{ [K in string]?: Schema }>,
R extends string,
A extends Schema | boolean | undefined,
> = {
[K in ElimString<R>]: TypeOfSchemaInternal<P[K]>;
} & {
[K in Exclude<ElimString<keyof P>, ElimString<R>>]?: TypeOfSchemaInternal<P[K]>;
} & ([A] extends [Schema] ? { [K in string]?: TypeOfSchemaInternal<A> }
: [A] extends [true] ? { [K in string]?: Value }
: unknown);
type UnionToIntersection<U> =
(U extends unknown ? (x: U) => never : never) extends (x: infer I) => never ? I : never;
type ElimString<T> = string extends T ? never : T;