Skip to content

types(populate): retain populated paths in toObject() and toJSON() unless depopulate: true set#16089

Open
vkarpov15 wants to merge 1 commit intomasterfrom
vkarpov15/gh-16085
Open

types(populate): retain populated paths in toObject() and toJSON() unless depopulate: true set#16089
vkarpov15 wants to merge 1 commit intomasterfrom
vkarpov15/gh-16085

Conversation

@vkarpov15
Copy link
Collaborator

Fix #16085

Summary

The populate typing fix now preserves populated path types through toObject() / toJSON() for document, query, and model populate() calls, while still returning the original raw path types for toObject({ depopulate: true }).

The primary change is a new PopulateDocumentResult type that returns a document with overwritten toObject() and toJSON() that accounts for populated paths

Examples

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Mongoose’s TypeScript populate typings so that populated path types are preserved through toObject() / toJSON() (for document, query, and model populate()), while still returning depopulated/raw path types when calling toObject({ depopulate: true }) / toJSON({ depopulate: true }).

Changes:

  • Introduces a PopulateDocumentResult helper type that overrides toObject() / toJSON() return types based on whether depopulate: true is set.
  • Updates Document.populate(), Document.$assertPopulated(), Model.populate(), and query populate result typing to return PopulateDocumentResult.
  • Adds type tests covering populated arrays and depopulate behavior for toObject().

Reviewed changes

Copilot reviewed 1 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
types/query.d.ts Wraps populated query document results in PopulateDocumentResult to preserve populated serialization typings.
types/populate.d.ts Adds PopulateDocumentResult (+ related helpers) to override toObject() / toJSON() return types based on depopulate.
types/models.d.ts Updates Model.populate<Paths>() return types to use PopulateDocumentResult.
types/document.d.ts Updates Document.populate() and $assertPopulated() return types to use PopulateDocumentResult.
test/types/populate.test.ts Adds compile-time assertions for populated array toObject() and depopulated toObject({ depopulate: true }).

Comment on lines +451 to +468
ExpectType<string | undefined>(populatedDoc.children[0]?.name);
const plainObject = populatedDoc.toObject();
ExpectType<string>(plainObject.children[0].name);
const depopulatedObject = populatedDoc.toObject({ depopulate: true });
ExpectType<Types.ObjectId>(depopulatedObject.children![0]);
});

ArrayParentModel.findOne({})
.populate<PopulatedChildren>('children')
.orFail()
.then(populatedDoc => {
ExpectAssignable<Document<any>>()(populatedDoc);
ExpectAssignable<Document<unknown>>()(populatedDoc);
ExpectType<string | undefined>(populatedDoc.children[0]?.name);
const plainObject = populatedDoc.toObject();
ExpectType<string>(plainObject.children[0].name);
const depopulatedObject = populatedDoc.toObject({ depopulate: true });
ExpectType<Types.ObjectId>(depopulatedObject.children![0]);
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hunk adds type assertions for toObject() and toObject({ depopulate: true }) on populated docs, but the PR also changes toJSON() typings. To prevent regressions, add equivalent assertions for toJSON() and toJSON({ depopulate: true }) on these populated results (doc.populate, query.populate, and Model.populate cases).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

toObject does not keep populated types

2 participants