Skip to content

Commit 6f316c0

Browse files
committed
types(middleware): make this in document middleware the hydrated doc type, not raw doc type
Fix #15242
1 parent 1a2faa7 commit 6f316c0

File tree

4 files changed

+85
-23
lines changed

4 files changed

+85
-23
lines changed

test/types/middleware.test.ts

+57
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,60 @@ function gh13601() {
200200
expectAssignable<Document>(this);
201201
});
202202
}
203+
204+
function gh15242() {
205+
type PostPersisted = {
206+
title: string,
207+
postTime: Date
208+
};
209+
210+
type ValidatorThis = DocumentValidatorThis | QueryValidatorThis;
211+
type DocumentValidatorThis = HydratedDocument<PostPersisted>;
212+
type QueryValidatorThis = Query<PostRecord, PostRecord>;
213+
214+
const PostSchema = new Schema<PostPersisted>({
215+
title: { type: String, required: true },
216+
postTime: {
217+
type: Date,
218+
required: true,
219+
validate: {
220+
validator: async function(this: ValidatorThis, postTime: Date): Promise<boolean> {
221+
return true;
222+
}
223+
}
224+
}
225+
});
226+
227+
type PostRecord = HydratedDocument<PostPersisted>;
228+
const PostModel = model<PostPersisted>('Post', PostSchema);
229+
}
230+
231+
function gh15242WithVirtuals() {
232+
type PostPersisted = {
233+
title: string,
234+
postTime: Date
235+
};
236+
237+
type ValidatorThis = DocumentValidatorThis | QueryValidatorThis;
238+
type DocumentValidatorThis = HydratedDocument<PostPersisted, { myVirtual: number }>;
239+
type QueryValidatorThis = Query<PostRecord, PostRecord>;
240+
241+
const PostSchema = new Schema({
242+
title: { type: String, required: true },
243+
postTime: {
244+
type: Date,
245+
required: true,
246+
validate: {
247+
validator: async function(this: ValidatorThis, postTime: Date): Promise<boolean> {
248+
if (!(this instanceof Query)) {
249+
expectType<number>(this.myVirtual);
250+
}
251+
return true;
252+
}
253+
}
254+
}
255+
}, { virtuals: { myVirtual: { get() { return 42; } } } });
256+
257+
type PostRecord = HydratedDocument<PostPersisted, { myVirtual: number }>;
258+
const PostModel = model<PostPersisted>('Post', PostSchema);
259+
}

types/index.d.ts

+14-14
Original file line numberDiff line numberDiff line change
@@ -541,21 +541,21 @@ declare module 'mongoose' {
541541
? DateSchemaDefinition
542542
: (Function | string);
543543

544-
export type SchemaDefinitionProperty<T = undefined, EnforcedDocType = any> = SchemaDefinitionWithBuiltInClass<T> |
545-
SchemaTypeOptions<T extends undefined ? any : T, EnforcedDocType> |
546-
typeof SchemaType |
547-
Schema<any, any, any> |
548-
Schema<any, any, any>[] |
549-
SchemaTypeOptions<T extends undefined ? any : Unpacked<T>, EnforcedDocType>[] |
550-
Function[] |
551-
SchemaDefinition<T, EnforcedDocType> |
552-
SchemaDefinition<Unpacked<T>, EnforcedDocType>[] |
553-
typeof Schema.Types.Mixed |
554-
MixedSchemaTypeOptions<EnforcedDocType>;
555-
556-
export type SchemaDefinition<T = undefined, EnforcedDocType = any> = T extends undefined
544+
export type SchemaDefinitionProperty<T = undefined, EnforcedDocType = any, THydratedDocumentType = HydratedDocument<EnforcedDocType>> = SchemaDefinitionWithBuiltInClass<T>
545+
| SchemaTypeOptions<T extends undefined ? any : T, EnforcedDocType, THydratedDocumentType>
546+
| typeof SchemaType
547+
| Schema<any, any, any>
548+
| Schema<any, any, any>[]
549+
| SchemaTypeOptions<T extends undefined ? any : Unpacked<T>, EnforcedDocType, THydratedDocumentType>[]
550+
| Function[]
551+
| SchemaDefinition<T, EnforcedDocType, THydratedDocumentType>
552+
| SchemaDefinition<Unpacked<T>, EnforcedDocType, THydratedDocumentType>[]
553+
| typeof Schema.Types.Mixed
554+
| MixedSchemaTypeOptions<EnforcedDocType>;
555+
556+
export type SchemaDefinition<T = undefined, EnforcedDocType = any, THydratedDocumentType = HydratedDocument<EnforcedDocType>> = T extends undefined
557557
? { [path: string]: SchemaDefinitionProperty; }
558-
: { [path in keyof T]?: SchemaDefinitionProperty<T[path], EnforcedDocType>; };
558+
: { [path in keyof T]?: SchemaDefinitionProperty<T[path], EnforcedDocType, THydratedDocumentType>; };
559559

560560
export type AnyArray<T> = T[] | ReadonlyArray<T>;
561561
export type ExtractMongooseArray<T> = T extends Types.Array<any> ? AnyArray<Unpacked<T>> : T;

types/schematypes.d.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ declare module 'mongoose' {
5656

5757
type DefaultType<T> = T extends Schema.Types.Mixed ? any : Partial<ExtractMongooseArray<T>>;
5858

59-
class SchemaTypeOptions<T, EnforcedDocType = any> {
59+
class SchemaTypeOptions<T, EnforcedDocType = any, THydratedDocumentType = HydratedDocument<EnforcedDocType>> {
6060
type?:
6161
T extends string ? StringSchemaDefinition :
6262
T extends number ? NumberSchemaDefinition :
@@ -65,19 +65,19 @@ declare module 'mongoose' {
6565
T extends Map<any, any> ? SchemaDefinition<typeof Map> :
6666
T extends Buffer ? SchemaDefinition<typeof Buffer> :
6767
T extends Types.ObjectId ? ObjectIdSchemaDefinition :
68-
T extends Types.ObjectId[] ? AnyArray<ObjectIdSchemaDefinition> | AnyArray<SchemaTypeOptions<ObjectId, EnforcedDocType>> :
69-
T extends object[] ? (AnyArray<Schema<any, any, any>> | AnyArray<SchemaDefinition<Unpacked<T>>> | AnyArray<SchemaTypeOptions<Unpacked<T>, EnforcedDocType>>) :
70-
T extends string[] ? AnyArray<StringSchemaDefinition> | AnyArray<SchemaTypeOptions<string, EnforcedDocType>> :
71-
T extends number[] ? AnyArray<NumberSchemaDefinition> | AnyArray<SchemaTypeOptions<number, EnforcedDocType>> :
72-
T extends boolean[] ? AnyArray<BooleanSchemaDefinition> | AnyArray<SchemaTypeOptions<boolean, EnforcedDocType>> :
73-
T extends Function[] ? AnyArray<Function | string> | AnyArray<SchemaTypeOptions<Unpacked<T>, EnforcedDocType>> :
68+
T extends Types.ObjectId[] ? AnyArray<ObjectIdSchemaDefinition> | AnyArray<SchemaTypeOptions<ObjectId, EnforcedDocType, THydratedDocumentType>> :
69+
T extends object[] ? (AnyArray<Schema<any, any, any>> | AnyArray<SchemaDefinition<Unpacked<T>>> | AnyArray<SchemaTypeOptions<Unpacked<T>, EnforcedDocType, THydratedDocumentType>>) :
70+
T extends string[] ? AnyArray<StringSchemaDefinition> | AnyArray<SchemaTypeOptions<string, EnforcedDocType, THydratedDocumentType>> :
71+
T extends number[] ? AnyArray<NumberSchemaDefinition> | AnyArray<SchemaTypeOptions<number, EnforcedDocType, THydratedDocumentType>> :
72+
T extends boolean[] ? AnyArray<BooleanSchemaDefinition> | AnyArray<SchemaTypeOptions<boolean, EnforcedDocType, THydratedDocumentType>> :
73+
T extends Function[] ? AnyArray<Function | string> | AnyArray<SchemaTypeOptions<Unpacked<T>, EnforcedDocType, THydratedDocumentType>> :
7474
T | typeof SchemaType | Schema<any, any, any> | SchemaDefinition<T> | Function | AnyArray<Function>;
7575

7676
/** Defines a virtual with the given name that gets/sets this path. */
7777
alias?: string | string[];
7878

7979
/** Function or object describing how to validate this schematype. See [validation docs](https://mongoosejs.com/docs/validation.html). */
80-
validate?: SchemaValidator<T, EnforcedDocType> | AnyArray<SchemaValidator<T, EnforcedDocType>>;
80+
validate?: SchemaValidator<T, EnforcedDocType, THydratedDocumentType> | AnyArray<SchemaValidator<T, EnforcedDocType, THydratedDocumentType>>;
8181

8282
/** Allows overriding casting logic for this individual path. If a string, the given string overwrites Mongoose's default cast error message. */
8383
cast?: string |

types/validation.d.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
declare module 'mongoose' {
22

3-
type SchemaValidator<T, EnforcedDocType> = RegExp | [RegExp, string] | Function | [Function, string] | ValidateOpts<T, EnforcedDocType> | ValidateOpts<T, EnforcedDocType>[];
3+
type SchemaValidator<T, EnforcedDocType, THydratedDocumentType> = RegExp
4+
| [RegExp, string]
5+
| Function
6+
| [Function, string]
7+
| ValidateOpts<T, THydratedDocumentType>
8+
| ValidateOpts<T, THydratedDocumentType>[];
49

510
interface ValidatorProps {
611
path: string;

0 commit comments

Comments
 (0)