Skip to content

Commit 89b3e78

Browse files
committed
WIP: Schema.fromDefinition() re: #13772
1 parent 70ddfd8 commit 89b3e78

File tree

3 files changed

+120
-61
lines changed

3 files changed

+120
-61
lines changed

test/types/methods.test.ts

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,54 @@
1-
import { Schema, Model, connection } from 'mongoose';
1+
import { Schema, Model, connection, HydratedDocumentFromSchema } from 'mongoose';
22

3-
interface ITest {
4-
foo: string;
5-
}
3+
function withInference() {
4+
const TestSchema = Schema.fromDefinition(
5+
{ foo: { type: String, required: true } },
6+
{
7+
methods: {
8+
getAnswer() {
9+
console.log(this.foo.trim());
10+
const num: number = (this as HydratedDocumentFromSchema<typeof TestSchema>).getAnswer();
11+
return 42;
12+
}
13+
}
14+
}
15+
);
16+
17+
const Test = connection.model('Test', TestSchema);
18+
19+
Test.create({ foo: 'test' });
20+
21+
const doc = new Test({ foo: 'test' });
622

7-
interface ITestMethods {
8-
getAnswer(): number;
23+
Math.floor(doc.getAnswer());
924
}
1025

11-
type ITestModel = Model<ITest, {}, ITestMethods>;
26+
function withGenerics() {
27+
interface ITest {
28+
foo: string;
29+
}
1230

13-
const TestSchema = new Schema<ITest, ITestModel, ITestMethods>({
14-
foo: { type: String, required: true }
15-
});
31+
interface ITestMethods {
32+
getAnswer(): number;
33+
}
1634

17-
TestSchema.methods.getAnswer = function(): number {
18-
console.log(this.foo.trim());
19-
return 42;
20-
};
35+
type ITestModel = Model<ITest, {}, ITestMethods>;
2136

22-
const Test = connection.model<ITest, ITestModel>('Test', TestSchema);
37+
const TestSchema = new Schema<ITest, ITestModel, ITestMethods>({
38+
foo: { type: String, required: true }
39+
});
2340

24-
Test.create({ foo: 'test' });
41+
TestSchema.methods.getAnswer = function(): number {
42+
console.log(this.foo.trim());
43+
const num: number = this.getAnswer();
44+
return 42;
45+
};
2546

26-
const doc = new Test({ foo: 'test' });
47+
const Test = connection.model<ITest, ITestModel>('Test', TestSchema);
2748

28-
Math.floor(doc.getAnswer());
49+
Test.create({ foo: 'test' });
50+
51+
const doc = new Test({ foo: 'test' });
52+
53+
Math.floor(doc.getAnswer());
54+
}

types/index.d.ts

Lines changed: 72 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,17 @@ declare module 'mongoose' {
8484
collection?: string,
8585
options?: CompileModelOptions
8686
): Model<
87-
InferSchemaType<TSchema>,
88-
ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
89-
ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>,
90-
ObtainSchemaGeneric<TSchema, 'TVirtuals'>,
91-
HydratedDocument<
92-
InferSchemaType<TSchema>,
93-
ObtainSchemaGeneric<TSchema, 'TVirtuals'> & ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>,
94-
ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
95-
ObtainSchemaGeneric<TSchema, 'TVirtuals'>
96-
>,
97-
TSchema
87+
InferSchemaType<TSchema>,
88+
ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
89+
ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>,
90+
ObtainSchemaGeneric<TSchema, 'TVirtuals'>,
91+
HydratedDocument<
92+
InferSchemaType<TSchema>,
93+
ObtainSchemaGeneric<TSchema, 'TVirtuals'> & ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>,
94+
ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
95+
ObtainSchemaGeneric<TSchema, 'TVirtuals'>
96+
>,
97+
TSchema
9898
> & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>;
9999

100100
export function model<T>(name: string, schema?: Schema<T, any, any> | Schema<T & Document, any, any>, collection?: string, options?: CompileModelOptions): Model<T>;
@@ -154,23 +154,23 @@ declare module 'mongoose' {
154154
DocType,
155155
any,
156156
TOverrides extends Record<string, never> ?
157-
Document<unknown, TQueryHelpers, DocType, TVirtuals> & Default__v<Require_id<DocType>> :
158-
IfAny<
159-
TOverrides,
160-
Document<unknown, TQueryHelpers, DocType, TVirtuals> & Default__v<Require_id<DocType>>,
161-
Document<unknown, TQueryHelpers, DocType, TVirtuals> & MergeType<
162-
Default__v<Require_id<DocType>>,
163-
TOverrides
164-
>
157+
Document<unknown, TQueryHelpers, DocType, TVirtuals> & Default__v<Require_id<DocType>> :
158+
IfAny<
159+
TOverrides,
160+
Document<unknown, TQueryHelpers, DocType, TVirtuals> & Default__v<Require_id<DocType>>,
161+
Document<unknown, TQueryHelpers, DocType, TVirtuals> & MergeType<
162+
Default__v<Require_id<DocType>>,
163+
TOverrides
165164
>
165+
>
166166
>;
167167
export type HydratedSingleSubdocument<
168168
DocType,
169169
TOverrides = {}
170170
> = IfAny<
171-
DocType,
172-
any,
173-
TOverrides extends Record<string, never> ?
171+
DocType,
172+
any,
173+
TOverrides extends Record<string, never> ?
174174
Types.Subdocument<unknown, Record<string, never>, DocType> & Require_id<DocType> :
175175
IfAny<
176176
TOverrides,
@@ -185,22 +185,22 @@ declare module 'mongoose' {
185185
DocType,
186186
any,
187187
TOverrides extends Record<string, never> ?
188-
Types.ArraySubdocument<unknown, Record<string, never>, DocType> & Require_id<DocType> :
189-
IfAny<
190-
TOverrides,
191-
Types.ArraySubdocument<unknown, Record<string, never>, DocType> & Require_id<DocType>,
192-
Types.ArraySubdocument<unknown, Record<string, never>, DocType> & MergeType<
193-
Require_id<DocType>,
194-
TOverrides
195-
>
188+
Types.ArraySubdocument<unknown, Record<string, never>, DocType> & Require_id<DocType> :
189+
IfAny<
190+
TOverrides,
191+
Types.ArraySubdocument<unknown, Record<string, never>, DocType> & Require_id<DocType>,
192+
Types.ArraySubdocument<unknown, Record<string, never>, DocType> & MergeType<
193+
Require_id<DocType>,
194+
TOverrides
196195
>
197-
>;
196+
>
197+
>;
198198

199199
export type HydratedDocumentFromSchema<TSchema extends Schema> = HydratedDocument<
200-
InferSchemaType<TSchema>,
201-
ObtainSchemaGeneric<TSchema, 'TInstanceMethods'> & ObtainSchemaGeneric<TSchema, 'TVirtuals'>,
202-
ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
203-
ObtainSchemaGeneric<TSchema, 'TVirtuals'>
200+
InferSchemaType<TSchema>,
201+
ObtainSchemaGeneric<TSchema, 'TInstanceMethods'> & ObtainSchemaGeneric<TSchema, 'TVirtuals'>,
202+
ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
203+
ObtainSchemaGeneric<TSchema, 'TVirtuals'>
204204
>;
205205

206206
export interface TagSet {
@@ -239,14 +239,14 @@ declare module 'mongoose' {
239239
export type DiscriminatorModel<M, T> = T extends Model<infer T, infer TQueryHelpers, infer TInstanceMethods, infer TVirtuals>
240240
?
241241
M extends Model<infer M, infer MQueryHelpers, infer MInstanceMethods, infer MVirtuals>
242-
? Model<Omit<M, keyof T> & T, MQueryHelpers | TQueryHelpers, MInstanceMethods | TInstanceMethods, MVirtuals | TVirtuals>
243-
: M
242+
? Model<Omit<M, keyof T> & T, MQueryHelpers | TQueryHelpers, MInstanceMethods | TInstanceMethods, MVirtuals | TVirtuals>
243+
: M
244244
: M;
245245

246246
export type DiscriminatorSchema<DocType, M, TInstanceMethods, TQueryHelpers, TVirtuals, TStaticMethods, DisSchema> =
247247
DisSchema extends Schema<infer DisSchemaEDocType, infer DisSchemaM, infer DisSchemaInstanceMethods, infer DisSchemaQueryhelpers, infer DisSchemaVirtuals, infer DisSchemaStatics>
248-
? Schema<MergeType<DocType, DisSchemaEDocType>, DiscriminatorModel<DisSchemaM, M>, DisSchemaInstanceMethods | TInstanceMethods, DisSchemaQueryhelpers | TQueryHelpers, DisSchemaVirtuals | TVirtuals, DisSchemaStatics & TStaticMethods>
249-
: Schema<DocType, M, TInstanceMethods, TQueryHelpers, TVirtuals, TStaticMethods>;
248+
? Schema<MergeType<DocType, DisSchemaEDocType>, DiscriminatorModel<DisSchemaM, M>, DisSchemaInstanceMethods | TInstanceMethods, DisSchemaQueryhelpers | TQueryHelpers, DisSchemaVirtuals | TVirtuals, DisSchemaStatics & TStaticMethods>
249+
: Schema<DocType, M, TInstanceMethods, TQueryHelpers, TVirtuals, TStaticMethods>;
250250

251251
type QueryResultType<T> = T extends Query<infer ResultType, any> ? ResultType : never;
252252

@@ -258,6 +258,8 @@ declare module 'mongoose' {
258258
TVirtuals,
259259
TStaticMethods> = (schema: Schema<DocType, M, TInstanceMethods, TQueryHelpers, TVirtuals, TStaticMethods>, opts?: any) => void;
260260

261+
type InferParam<T, K> = K extends keyof T ? T[K] : {};
262+
261263
export class Schema<
262264
RawDocType = any,
263265
TModelType = Model<RawDocType, any, any, any>,
@@ -284,6 +286,37 @@ declare module 'mongoose' {
284286
/** Adds key path / schema type pairs to this schema. */
285287
add(obj: SchemaDefinition<SchemaDefinitionType<RawDocType>, RawDocType> | Schema, prefix?: string): this;
286288

289+
static fromDefinition<
290+
MySchemaDef,
291+
MySchemaOptions extends SchemaOptions<
292+
InferRawDocType<MySchemaDef>,
293+
InferParam<MySchemaOptions, 'methods'>,
294+
{},
295+
{},
296+
InferParam<MySchemaOptions, 'virtuals'>,
297+
HydratedDocument<InferRawDocType<MySchemaDef>, InferParam<MySchemaOptions, 'methods'>, {}, InferParam<MySchemaOptions, 'virtuals'>>
298+
>,
299+
TMethods = InferParam<MySchemaOptions, 'methods'>,
300+
TVirtuals = InferParam<MySchemaOptions, 'virtuals'>,
301+
TStatics = InferParam<MySchemaOptions, 'statics'>
302+
>(
303+
schemaDefinition: MySchemaDef,
304+
options: MySchemaOptions
305+
): Schema<
306+
InferRawDocType<MySchemaDef>,
307+
Model<
308+
InferRawDocType<MySchemaDef>,
309+
{},
310+
TMethods,
311+
TVirtuals
312+
> & TStatics,
313+
TMethods,
314+
{},
315+
TVirtuals,
316+
TStatics,
317+
MySchemaOptions
318+
>;
319+
287320
/**
288321
* Add an alias for `path`. This means getting or setting the `alias`
289322
* is equivalent to getting or setting the `path`.

types/schemaoptions.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,10 @@ declare module 'mongoose' {
227227
* Document instance methods.
228228
*/
229229
methods?: IfEquals<
230-
TInstanceMethods,
231-
{},
232-
Record<any, (this: THydratedDocumentType, ...args: any) => unknown>,
233-
AddThisParameter<TInstanceMethods, THydratedDocumentType> & AnyObject
230+
TInstanceMethods,
231+
{},
232+
Record<any, (this: THydratedDocumentType, ...args: any) => unknown>,
233+
AddThisParameter<TInstanceMethods, THydratedDocumentType> & AnyObject
234234
>
235235

236236
/**

0 commit comments

Comments
 (0)