Skip to content

Breaking TypeScript Change in find from v8.5.5 to v8.6.0 #14863

@Towerss

Description

@Towerss

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

8.6.0

Node.js version

20.15.1

MongoDB server version

7

Typescript version (if applicable)

5.5.4

Description

Hi Mongoose team,

Mongoose version 8.6.0 introduced a breaking change in the type definitions for the find method. The filter parameter type was changed from FilterQuery to RootFilterQuery, which no longer allows fields or operators that are not explicitly defined in the schema.

This change significantly affects the use of generic utility functions in TypeScript. For example, functions designed to operate across multiple Mongoose models with different schemas (using a generic Model) now fail to compile when using dynamically added fields or common filters that are not explicitly declared in every schema.

Previously, the more permissive FilterQuery allowed such flexibility, enabling code reuse and reducing code duplication across models. The stricter typing of RootFilterQuery now forces developers to either:

  • Refrain from using dynamic fields or filters that are not explicitly defined in the schema.

  • Resort to less type-safe workarounds, such as using type assertions or @ts-ignore, to bypass TypeScript errors.

Steps to Reproduce

  1. Initialize a new Node.js project with TypeScript and install Mongoose version 8.5.5
  2. Define a Mongoose schema and a function that uses find with a filter containing fields that might not be strictly defined in the schema:
import mongoose, { Schema, Document, Model, Types } from 'mongoose';

// Define a simple schema with a limited number of fields
interface ExampleDoc extends Document {
  isActive: boolean;
  isCustom: boolean;
}

const ExampleSchema = new Schema<ExampleDoc>({
  isActive: Boolean,
  isCustom: Boolean
});

const ExampleModel: Model<ExampleDoc> = mongoose.model<ExampleDoc>('Example', ExampleSchema);

async function initializeRelatedParametersHelper<T extends Document>(
  model: Model<T>,
  createdForId: Types.ObjectId,
  createdForType: string,
  trainingZoneId: Types.ObjectId
): Promise<void> {
  // This should work in version 8.5.5 but throws an error in 8.6.0
  const defaults = await model
    .find({
      createdForType: 'system', // This field is not defined in ExampleSchema
      isActive: true,
      isCustom: false,
    })
    .lean()
    .exec();

  for (const defaultParam of defaults) {
    const newParam = new model({
      ...defaultParam,
      createdForId,
      createdForType,
      trainingZoneId,
      isCustom: false,
    });
    await newParam.save();
  }
}
  1. Compile and Run with Mongoose Version 8.5.5. The code should compile without errors.
  2. Upgrade to Mongoose Version 8.6.0
  3. Recompile the TypeScript code and observe the TypeScript error: Object literal may only specify known properties, and 'createdForType' does not exist in type 'RootFilterQuery'.

Expected Behavior

TypeScript should compile without errors, allowing the flexibility to use generic utility functions across different models with dynamic fields or query parameters not strictly defined in the schema.

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionIf you have any thoughts or comments on this issue, please share them!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions