Skip to content

types(models): propagate inferred Model type to QueryWithHelpers to support methods on docs returned from statics#16233

Closed
vkarpov15 wants to merge 2 commits intomasterfrom
vkarpov15/gh-15532
Closed

types(models): propagate inferred Model type to QueryWithHelpers to support methods on docs returned from statics#16233
vkarpov15 wants to merge 2 commits intomasterfrom
vkarpov15/gh-15532

Conversation

@vkarpov15
Copy link
Copy Markdown
Collaborator

@vkarpov15 vkarpov15 commented Apr 21, 2026

Fix #15532

Summary

#15532 pointed out that if you have a model static that returns a query, the resulting document will not have methods if you are using automatic schema inference. This PR makes all model functions that return queries infer the model type from this, which seems to solve the issue. By inferring this, Mongoose models can get the "real model type" when creating the query.

Examples

…upport methods on docs returned from statics

Fix #15532
Copy link
Copy Markdown
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 model method typings so that when a model static returns a query, the query’s inferred document type can be derived from this (the concrete model), preserving instance method typings on documents returned from statics (fixes #15532).

Changes:

  • Introduces helper types to derive the result document type from the calling model constructor (this).
  • Updates many Model query-returning methods (e.g. findOne, find, findById, updateOne, distinct, etc.) to infer the “doc type” parameter for QueryWithHelpers from this.
  • Adds a TypeScript regression test case for #15532.

Reviewed changes

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

File Description
types/models.d.ts Propagates model-derived result doc types through QueryWithHelpers via this-inferred generics.
test/types/models.test.ts Adds a type-level regression test intended to cover #15532 behavior.

Comment thread test/types/models.test.ts
expect(foundDocsAfterUpdate[0].updateName('bar')).type.toBe<Promise<UserModel>>();

const foundDocsAfterDistinct = await UserModel.distinct('name').find({ name: 'foo' });
expect(foundDocsAfterDistinct[0].updateName('baz')).type.toBe<Promise<UserModel>>();
Copy link
Copy Markdown
Collaborator

@hasezoey hasezoey left a comment

Choose a reason for hiding this comment

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

This at first glance this looks good, but this somehow changes the return type of Model.findOne()(and likely others) to be Class instead of Document<Class>. This happens when the model type is manually created by using Model</**/> & typeof Class for adding statics onto the model. This is used by typegoose currently. Example Code:

async function repro() {
  class TestClass {
    public someProp!: string;

    // the following functions do not affect the type, but are here for illustrative purposes
    someFunc(this: HydratedDocument<TestClass>) {
      return this.someProp;
    }

    static someStaticFunc(this: TestClassModel) {
      return this.findOne();
    }
  }

  const schema = new Schema({ someProp: String });
  schema.loadClass(TestClass);

  type TestClassModel = Model<TestClass> & typeof TestClass;
  const model = mongoose.model('test', schema) as TestClassModel;

  // Type: const foundDoc: TestClass | null
  // Should be: const foundDoc: Document<TestClass> | null
  const foundDoc = await model.findOne();

  // Type: const foundDoc: TestClass | null
  // Should be: const foundDoc: Document<TestClass> | null
  const anotherDoc = await model.someStaticFunc();
}

Edit: i found a workaround (might also be recommended, if i look at typescript: statics) changing & typeof Class to Pick<typeof Class, keyof typeof Class>

@hasezoey hasezoey added the typescript Types or Types-test related issue / Pull Request label Apr 23, 2026
@vkarpov15
Copy link
Copy Markdown
Collaborator Author

I'm going to close this PR for now and consider alternative approaches. Copilot's comment is valid: as written, this PR does nothing for new Schema({}, { methods, statics }). Only helps in the extends BaseUserModel case, which is not our #1 recommended approach right now. We will take another pass at #15532 later.

@vkarpov15 vkarpov15 closed this Apr 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

typescript Types or Types-test related issue / Pull Request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Document method types are missing methods when queried from statics

3 participants