Skip to content

Commit dcd3435

Browse files
committed
types(model+query): avoid stripping out virtuals when calling populate with paths generic
Fix Automattic#15111
1 parent 4081e5c commit dcd3435

File tree

3 files changed

+194
-97
lines changed

3 files changed

+194
-97
lines changed

test/types/populate.test.ts

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import mongoose, { Schema, model, Document, PopulatedDoc, Types, HydratedDocument, SchemaTypeOptions } from 'mongoose';
1+
import mongoose, { Schema, model, Document, PopulatedDoc, Types, HydratedDocument, SchemaTypeOptions, Model } from 'mongoose';
22
// Use the mongodb ObjectId to make instanceof calls possible
33
import { ObjectId } from 'mongodb';
44
import { expectAssignable, expectError, expectType } from 'tsd';
@@ -459,3 +459,100 @@ async function gh14574() {
459459
expectType<string>(user.fullName());
460460
expectType<string>(user.friend.fullName());
461461
}
462+
463+
async function gh15111() {
464+
interface IChild {
465+
_id: Types.ObjectId;
466+
name: string;
467+
}
468+
469+
type ChildDocumentOverrides = {};
470+
471+
interface IChildVirtuals {
472+
id: string;
473+
}
474+
475+
type ChildInstance = HydratedDocument<
476+
IChild,
477+
ChildDocumentOverrides & IChildVirtuals
478+
>;
479+
480+
type ChildModelType = Model<
481+
IChild,
482+
{},
483+
ChildDocumentOverrides,
484+
IChildVirtuals,
485+
ChildInstance
486+
>;
487+
const childSchema = new Schema<IChild, ChildModelType>(
488+
{
489+
name: {
490+
type: 'String',
491+
required: true,
492+
trim: true
493+
}
494+
},
495+
{
496+
optimisticConcurrency: true
497+
}
498+
);
499+
const ChildModel = mongoose.model<IChild, ChildModelType>('Child', childSchema);
500+
501+
interface IParent {
502+
_id: Types.ObjectId;
503+
name: string;
504+
surname: string;
505+
child: PopulatedDoc<Document<Types.ObjectId> & IChild>;
506+
}
507+
508+
type ParentDocumentOverrides = {};
509+
510+
interface IParentVirtuals {
511+
id: string;
512+
fullName: string;
513+
}
514+
515+
type ParentInstance = HydratedDocument<
516+
IParent,
517+
ParentDocumentOverrides & IParentVirtuals
518+
>;
519+
520+
type ParentModelType = Model<
521+
IParent,
522+
{},
523+
ParentDocumentOverrides,
524+
IParentVirtuals,
525+
ParentInstance
526+
>;
527+
const parentSchema = new Schema<IParent, ParentModelType>(
528+
{
529+
name: {
530+
type: 'String',
531+
required: true,
532+
trim: true
533+
},
534+
surname: {
535+
type: 'String',
536+
required: true,
537+
trim: true
538+
},
539+
child: {
540+
type: 'ObjectId',
541+
ref: 'Child',
542+
required: true
543+
}
544+
},
545+
{ optimisticConcurrency: true }
546+
);
547+
548+
parentSchema.virtual('fullName').get(function() {
549+
return `${this.name} ${this.surname}`;
550+
});
551+
552+
const ParentModel = mongoose.model<IParent, ParentModelType>('Parent', parentSchema);
553+
554+
const parents = await ParentModel.find().populate<{ child: ChildInstance }>(
555+
'child'
556+
);
557+
expectType<string>(parents[0].fullName);
558+
}

0 commit comments

Comments
 (0)