From 1e652c62f1887c4ab06409e42777df9328ab40d3 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 7 May 2024 09:47:16 -0400 Subject: [PATCH 1/4] docs(typescript): clarify that setting THydratedDocumentType on schemas is necessary for correct method context Fix #14573 --- docs/typescript/schemas.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index e6397cbc6cf..6782d183e78 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -164,7 +164,7 @@ This is because Mongoose has numerous features that add paths to your schema tha ## Arrays When you define an array in a document interface, we recommend using vanilla JavaScript arrays, **not** Mongoose's `Types.Array` type or `Types.DocumentArray` type. -Instead, use the `THydratedDocumentType` generic to define that the hydrated document type has paths of type `Types.Array` and `Types.DocumentArray`. +Instead, use the `THydratedDocumentType` generic for models and schemas to define that the hydrated document type has paths of type `Types.Array` and `Types.DocumentArray`. ```typescript import mongoose from 'mongoose' @@ -178,17 +178,27 @@ interface IOrder { // for fully hydrated docs returned from `findOne()`, etc. type OrderHydratedDocument = mongoose.HydratedDocument< IOrder, - { tags: mongoose.Types.DocumentArray<{ name: string }> } + { tags: mongoose.HydratedArraySubdocument<{ name: string }> } >; type OrderModelType = mongoose.Model< IOrder, {}, {}, {}, - OrderHydratedDocument + OrderHydratedDocument // THydratedDocumentType >; -const orderSchema = new mongoose.Schema({ +const orderSchema = new mongoose.Schema< + IOrder, + OrderModelType, + {}, // methods + {}, // query helpers + {}, // virtuals + {}, // statics + mongoose.DefaultSchemaOptions, // schema options + IOrder, // doctype + OrderHydratedDocument // THydratedDocumentType +>({ tags: [{ name: { type: String, required: true } }] }); const OrderModel = mongoose.model('Order', orderSchema); @@ -207,3 +217,8 @@ async function run() { leanDoc.tags; // Array<{ name: string }> }; ``` + +Use `HydratedArraySubdocument` for the type of array subdocuments, and `HydratedSingleSubdocument` for single subdocuments. + +If you are not using [schema methods](../guide.html#methods) or [virtuals](../tutorials/virtuals.html), you can omit the last 7 generic parameters to `Schema()` and just define your schema using `new mongoose.Schema(...)`. +The THydratedDocumentType parameter for schemas is primarily for setting the value of `this` on methods and virtuals. \ No newline at end of file From c8029090946bd8598f4d72ce9187dd27437d7973 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 7 May 2024 09:57:25 -0400 Subject: [PATCH 2/4] test(types): add test case for #14573 --- test/types/schema.test.ts | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index b919e68e6ec..8deb72a6eda 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -1,4 +1,6 @@ import { + DefaultSchemaOptions, + HydratedSingleSubdocument, Schema, Document, HydratedDocument, @@ -1442,3 +1444,53 @@ function gh14367() { flags: [true] }; } + +function gh14573() { + interface Names { + _id: Types.ObjectId; + firstName: string; + } + + // Document definition + interface User { + names: Names; + } + + // Define property overrides for hydrated documents + type THydratedUserDocument = { + names?: HydratedSingleSubdocument; + }; + + type UserMethods = { + getName(): Names | undefined; + }; + + type UserModelType = Model; + + const userSchema = new Schema< + User, + UserModelType, + UserMethods, + {}, + {}, + {}, + DefaultSchemaOptions, + User, + THydratedUserDocument + >( + { + names: new Schema({ firstName: String }) + }, + { + methods: { + getName() { + const str: string | undefined = this.names?.firstName; + return this.names?.toObject(); + } + } + } + ); + const UserModel = model('User', userSchema); + const doc = new UserModel({ names: { _id: '0'.repeat(24), firstName: 'foo' } }); + doc.names?.ownerDocument(); +} From 9b449d66dab6f2fbe2c9ef7c7bcb7bc3aa0a0f65 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 7 May 2024 10:00:01 -0400 Subject: [PATCH 3/4] docs: clarify that middleware context also relies on Schema THydratedDocumentType --- docs/typescript/schemas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index 6782d183e78..a34cd1eba21 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -220,5 +220,5 @@ async function run() { Use `HydratedArraySubdocument` for the type of array subdocuments, and `HydratedSingleSubdocument` for single subdocuments. -If you are not using [schema methods](../guide.html#methods) or [virtuals](../tutorials/virtuals.html), you can omit the last 7 generic parameters to `Schema()` and just define your schema using `new mongoose.Schema(...)`. +If you are not using [schema methods](../guide.html#methods), middleware, or [virtuals](../tutorials/virtuals.html), you can omit the last 7 generic parameters to `Schema()` and just define your schema using `new mongoose.Schema(...)`. The THydratedDocumentType parameter for schemas is primarily for setting the value of `this` on methods and virtuals. \ No newline at end of file From e2b0e12713c42e77c97381379cb51b847b42336b Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 9 May 2024 11:15:01 -0400 Subject: [PATCH 4/4] Update docs/typescript/schemas.md Co-authored-by: hasezoey --- docs/typescript/schemas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/typescript/schemas.md b/docs/typescript/schemas.md index a34cd1eba21..e4127ce1621 100644 --- a/docs/typescript/schemas.md +++ b/docs/typescript/schemas.md @@ -221,4 +221,4 @@ async function run() { Use `HydratedArraySubdocument` for the type of array subdocuments, and `HydratedSingleSubdocument` for single subdocuments. If you are not using [schema methods](../guide.html#methods), middleware, or [virtuals](../tutorials/virtuals.html), you can omit the last 7 generic parameters to `Schema()` and just define your schema using `new mongoose.Schema(...)`. -The THydratedDocumentType parameter for schemas is primarily for setting the value of `this` on methods and virtuals. \ No newline at end of file +The THydratedDocumentType parameter for schemas is primarily for setting the value of `this` on methods and virtuals.