/
inferschematype.d.ts
164 lines (151 loc) · 7.94 KB
/
inferschematype.d.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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import { Schema, Types, InferSchemaType, ObtainDocumentType, SchemaDefinitionProperty, SchemaType, SchemaTypeOptions, TypeKeyBaseType } from 'mongoose';
declare module 'mongoose' {
/**
* @summary Obtains document schema type.
* @description Obtains document schema type from document Definition OR returns enforced schema type if it's provided.
* @param {DocDefinition} DocDefinition A generic equals to the type of document definition "provided in as first parameter in Schema constructor".
* @param {EnforcedDocType} EnforcedDocType A generic type enforced by user "provided before schema constructor".
* @param {TypeKey} TypeKey A generic of literal string type.
*/
type ObtainDocumentType<DocDefinition, EnforcedDocType = any, TypeKey extends TypeKeyBaseType = DefaultTypeKey> =
IsItRecordAndNotAny<EnforcedDocType> extends true ? EnforcedDocType : {
[K in keyof (RequiredPaths<DocDefinition, TypeKey> &
OptionalPaths<DocDefinition, TypeKey>)]: ObtainDocumentPathType<DocDefinition[K], TypeKey>;
};
/**
* @summary Obtains document schema type from Schema instance.
* @param {SchemaType} SchemaType A generic of schema type instance.
* @example
* const userSchema = new Schema({userName:String});
* type UserType = InferSchemaType<typeof userSchema>;
* // result
* type UserType = {userName?: string}
*/
type InferSchemaType<SchemaType> = ObtainSchemaGeneric<SchemaType, 'DocType'>;
/**
* @summary Obtains schema Generic type by using generic alias.
* @param {TSchema} TSchema A generic of schema type instance.
* @param {alias} alias Targeted generic alias.
*/
type ObtainSchemaGeneric<TSchema, alias extends 'EnforcedDocType' | 'M' | 'TInstanceMethods' | 'TQueryHelpers' | 'TVirtuals' | 'TStaticMethods' | 'TPathTypeKey' | 'DocType'> =
TSchema extends Schema<infer EnforcedDocType, infer M, infer TInstanceMethods, infer TQueryHelpers, infer TVirtuals, infer TStaticMethods, infer TPathTypeKey, infer DocType>
? {
EnforcedDocType: EnforcedDocType;
M: M;
TInstanceMethods: TInstanceMethods;
TQueryHelpers: TQueryHelpers;
TVirtuals: TVirtuals;
TStaticMethods: TStaticMethods;
TPathTypeKey: TPathTypeKey;
DocType: DocType;
}[alias]
: unknown;
}
/**
* @summary Checks if a type is "Record" or "any".
* @description It Helps to check if user has provided schema type "EnforcedDocType"
* @param {T} T A generic type to be checked.
* @returns true if {@link T} is Record OR false if {@link T} is of any type.
*/
type IsItRecordAndNotAny<T> = IfEquals<T, any, false, T extends Record<any, any> ? true : false>;
/**
* @summary Checks if two types are identical.
* @param {T} T The first type to be compared with {@link U}.
* @param {U} U The seconde type to be compared with {@link T}.
* @param {Y} Y A type to be returned if {@link T} & {@link U} are identical.
* @param {N} N A type to be returned if {@link T} & {@link U} are not identical.
*/
type IfEquals<T, U, Y = true, N = false> =
(<G>() => G extends T ? 1 : 0) extends
(<G>() => G extends U ? 1 : 0) ? Y : N;
/**
* @summary Required path base type.
* @description It helps to check whereas if a path is required OR optional.
*/
type RequiredPathBaseType = { required: true | [true, string | undefined] };
/**
* @summary Path base type defined by using TypeKey
* @description It helps to check if a path is defined by TypeKey OR not.
* @param {TypeKey} TypeKey A literal string refers to path type property key.
*/
type PathWithTypePropertyBaseType<TypeKey extends TypeKeyBaseType, T = any> = {
[k in TypeKey]: T;
};
/**
* @summary A Utility to obtain schema's required path keys.
* @param {T} T A generic refers to document definition.
* @returns required paths keys of document definition.
*/
type RequiredPathKeys<T, TypeKey extends TypeKeyBaseType> = {
[K in keyof T]: T[K] extends RequiredPathBaseType ? IfEquals<T[K], any, never, K>
: T[K] extends PathWithTypePropertyBaseType<TypeKey, any[]>
? T[K] extends { default: undefined } ? never : K
: never;
}[keyof T];
/**
* @summary A Utility to obtain schema's required paths.
* @param {T} T A generic refers to document definition.
* @returns a record contains required paths with the corresponding type.
*/
type RequiredPaths<T, TypeKey extends TypeKeyBaseType> = {
[K in RequiredPathKeys<T, TypeKey>]: T[K];
};
/**
* @summary A Utility to obtain schema's optional path keys.
* @param {T} T A generic refers to document definition.
* @returns optional paths keys of document definition.
*/
type OptionalPathKeys<T, TypeKey extends TypeKeyBaseType> = {
[K in keyof T]: T[K] extends RequiredPathBaseType ? never :
T[K] extends PathWithTypePropertyBaseType<TypeKey, any[]>
? T[K] extends { default: undefined } ? K : never
: K;
}[keyof T];
/**
* @summary A Utility to obtain schema's optional paths.
* @param {T} T A generic refers to document definition.
* @returns a record contains optional paths with the corresponding type.
*/
type OptionalPaths<T, TypeKey extends TypeKeyBaseType> = {
[K in OptionalPathKeys<T, TypeKey>]?: T[K];
};
/**
* @summary Obtains schema Path type.
* @description Obtains Path type by calling {@link ResolvePathType} OR by calling {@link InferSchemaType} if path of schema type.
* @param {PathValueType} PathValueType Document definition path type.
* @param {TypeKey} TypeKey A generic refers to document definition.
*/
type ObtainDocumentPathType<PathValueType, TypeKey extends TypeKeyBaseType> = PathValueType extends Schema<any>
? InferSchemaType<PathValueType>
: PathValueType extends PathWithTypePropertyBaseType<TypeKey, Schema<any>>
? InferSchemaType<PathValueType[TypeKey]>
: ResolvePathType<
TypeKey,
PathValueType extends PathWithTypePropertyBaseType<TypeKey> ? PathValueType[TypeKey] : PathValueType,
PathValueType extends PathWithTypePropertyBaseType<TypeKey> ? Omit<PathValueType, TypeKey> : {}
>;
/**
* @param {T} T A generic refers to string path enums.
* @returns Path enum values type as literal strings or string.
*/
type PathEnumOrString<T extends SchemaTypeOptions<string>['enum']> = T extends (infer E)[] ? E : T extends { values: any } ? PathEnumOrString<T['values']> : string;
/**
* @summary Resolve path type by returning the corresponding type.
* @param {PathValueType} PathValueType Document definition path type.
* @param {Options} Options Document definition path options except path type.
* @returns Number, "Number" or "number" will be resolved to string type.
*/
type ResolvePathType<TypeKey extends TypeKeyBaseType, PathValueType, Options extends SchemaTypeOptions<PathValueType> = {}> =
PathValueType extends (infer Item)[] ? IfEquals<Item, never, any, ObtainDocumentPathType<Item, TypeKey>>[] :
PathValueType extends { [K: string]: SchemaDefinitionProperty } ? ObtainDocumentType<PathValueType, any, TypeKey> :
PathValueType extends StringConstructor | 'string' | 'String' | typeof Schema.Types.String ? PathEnumOrString<Options['enum']> :
PathValueType extends NumberConstructor | 'number' | 'Number' | typeof Schema.Types.Number ? number :
PathValueType extends DateConstructor | 'date' | 'Date' | typeof Schema.Types.Date ? Date :
PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer :
PathValueType extends BooleanConstructor | 'boolean' | 'Boolean' | typeof Schema.Types.Boolean ? boolean :
PathValueType extends 'objectId' | 'ObjectId' | typeof Schema.Types.ObjectId ? Types.ObjectId :
PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 :
PathValueType extends MapConstructor ? Map<string, ResolvePathType<TypeKey, Options['of']>> :
PathValueType extends ArrayConstructor ? any[] :
PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
unknown;