Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript does not return an error when assigning the result of a lean query to a variable of type InstanceType<Model<MyModel>> #14697

Closed
2 tasks done
nikzanda opened this issue Jun 28, 2024 · 4 comments · Fixed by #14734
Labels
typescript Types or Types-test related issue / Pull Request
Milestone

Comments

@nikzanda
Copy link

nikzanda commented Jun 28, 2024

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.4.4

Node.js version

20.10.0

MongoDB server version

6.0.2

Typescript version (if applicable)

5.4.5

Description

Reproduction link: https://stackblitz.com/edit/stackblitz-starters-9hjjfm?file=src%2Findex.ts

TypeScript should not allow me to assign the result of await UserModel.findOne().lean(); to the variable let user: UserInstance | null = null; in fact, the user.set or user.save instruction results in an error.

  let user: UserInstance | null = null;
  if (condition) {
    user = await UserModel.findOne().lean(); // Here it should report an error
    if (user) {
      user.set({
        name: 'John Doe',
      });
      await user.save();
    }
  }

The code below
image
image

results in an error when executed:
Screenshot 2024-06-28 at 18 24 06

Steps to Reproduce

  • Declare a variable of type InstanceType<Model<MyModel>>;
  • Assign the result of await MyModel.findOne().lean();
  • Call .set({ ... }) or .save() function of the variabile.

Expected Behavior

TypeScript should not allow the code to compile

@IslandRhythms IslandRhythms added the typescript Types or Types-test related issue / Pull Request label Jul 2, 2024
@IslandRhythms
Copy link
Collaborator

IslandRhythms commented Jul 2, 2024

import {
    Schema,
    connection,
    connect,
    Model,
    model,
    SchemaOptions,
    SchemaTypes,
  } from 'mongoose';
  
  export interface IUser {
    name: string;
    createdAt: Date;
    updatedAt: Date;
  }
  
  export interface IUserVirtuals {
    id: string;
  }
  
  type UserModelType = Model<IUser, {}, {}, IUserVirtuals>;
  
  export type UserInstance = InstanceType<UserModelType>;
  
  const options: SchemaOptions<IUser> = {
    timestamps: true,
    optimisticConcurrency: true,
  };

  const userSchema = new Schema<IUser, UserModelType>(
    {
      name: {
        type: SchemaTypes.String,
        required: true,
        trim: true,
      },
    },
    options
  );

  const User = model<IUser, UserModelType>('User', userSchema);

  async function run() {
    await connect('mongodb://localhost:27017');
    await connection.dropDatabase();

    await User.create({
        name: 'John',
      });
    
    
      let user: UserInstance | null = null;
      user = await User.findOne().lean();
        if (user) {
          user.name = 'John Doe'
          await user.save();
        }
    console.log(user);
  }

  run();

@nikzanda
Copy link
Author

nikzanda commented Jul 2, 2024

await User.create({
        name: 'John',
      });
    
    
      let user: UserInstance | null = null;
      user = await User.findOne().lean();
        if (user) {
          user.name = 'John Doe'
          await user.save();
        }
    console.log(user);

Sorry, but your code does not work, as the documentation states:

The lean option tells Mongoose to skip hydrating the result documents. This makes queries faster and less memory intensive, but the result documents are plain old JavaScript objects (POJOs), not Mongoose documents.

Therefore, the save method cannot be called and TypeScript does not report any errors:

Screenshot 2024-07-02 at 20 47 51

@Automattic Automattic deleted a comment from IslandRhythms Jul 2, 2024
@vkarpov15 vkarpov15 added this to the 8.4.5 milestone Jul 2, 2024
@vkarpov15
Copy link
Collaborator

As a workaround, you can do user = await User.findOne().lean<IUser>();. I'm investigating why this issue is happening.

@nikzanda
Copy link
Author

nikzanda commented Jul 2, 2024

Thank you

@vkarpov15 vkarpov15 modified the milestones: 8.4.5, 8.4.6 Jul 3, 2024
vkarpov15 added a commit that referenced this issue Jul 9, 2024
@vkarpov15 vkarpov15 modified the milestones: 8.4.6, 8.6 Jul 9, 2024
vkarpov15 added a commit that referenced this issue Jul 10, 2024
types: avoid automatically inferring lean result type when assigning to explicitly typed variable
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
3 participants