diff --git a/test/schema.test.js b/test/schema.test.js index 8cd58ba7b9f..3076c9df62a 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -3258,4 +3258,24 @@ describe('schema', function() { await q; }); + + it('supports casting object to subdocument (gh-14748) (gh-9076)', function() { + const nestedSchema = new Schema({ name: String }); + nestedSchema.methods.getAnswer = () => 42; + + const schema = new Schema({ + arr: [nestedSchema], + singleNested: nestedSchema + }); + + // Cast to doc array + let subdoc = schema.path('arr').cast([{ name: 'foo' }])[0]; + assert.ok(subdoc instanceof mongoose.Document); + assert.equal(subdoc.getAnswer(), 42); + + // Cast to single nested subdoc + subdoc = schema.path('singleNested').cast({ name: 'bar' }); + assert.ok(subdoc instanceof mongoose.Document); + assert.equal(subdoc.getAnswer(), 42); + }); }); diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 9dab60d2022..a9679c082b8 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -1,5 +1,6 @@ import { DefaultSchemaOptions, + HydratedArraySubdocument, HydratedSingleSubdocument, Schema, Document, @@ -1555,3 +1556,22 @@ function gh14696() { }); } + +function gh14748() { + const nestedSchema = new Schema({ name: String }); + + const schema = new Schema({ + arr: [nestedSchema], + singleNested: nestedSchema + }); + + const subdoc = schema.path('singleNested') + .cast>({ name: 'bar' }); + expectAssignable<{ name: string }>(subdoc); + + const subdoc2 = schema.path('singleNested').cast({ name: 'bar' }); + expectAssignable<{ name: string }>(subdoc2); + + const subdoc3 = schema.path>('singleNested').cast({ name: 'bar' }); + expectAssignable<{ name: string }>(subdoc3); +} diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index b7f1fc733b9..e8a0ecffdf0 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -220,7 +220,8 @@ declare module 'mongoose' { OptionsConstructor: SchemaTypeOptions; /** Cast `val` to this schema type. Each class that inherits from schema type should implement this function. */ - cast(val: any, doc: Document, init: boolean, prev?: any, options?: any): any; + cast(val: any, doc?: Document, init?: boolean, prev?: any, options?: any): any; + cast(val: any, doc?: Document, init?: boolean, prev?: any, options?: any): ResultType; /** Sets a default value for this SchemaType. */ default(val: any): any; @@ -443,7 +444,7 @@ declare module 'mongoose' { defaultOptions: Record; } - class Subdocument extends SchemaType implements AcceptsDiscriminator { + class Subdocument extends SchemaType implements AcceptsDiscriminator { /** This schema type's name, to defend against minifiers that mangle function names. */ static schemaName: string; @@ -455,6 +456,8 @@ declare module 'mongoose' { discriminator(name: string | number, schema: Schema, value?: string): U; discriminator(name: string | number, schema: Schema, value?: string): Model; + + cast(val: any, doc?: Document, init?: boolean, prev?: any, options?: any): HydratedSingleSubdocument; } class String extends SchemaType {