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

Properties with unknown type in the mongoose model when set timestamps to true in v6.8.0 #12807

Open
2 tasks done
Code-Mythos opened this issue Dec 16, 2022 · 9 comments
Open
2 tasks done
Labels
typescript Types or Types-test related issue / Pull Request

Comments

@Code-Mythos
Copy link

Code-Mythos commented Dec 16, 2022

Prerequisites

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

Mongoose version

6.8.0

Node.js version

16.15.1

MongoDB server version

6.0

Typescript version (if applicable)

4.9.4

Description

In version 6.8.0, when I set the timestamps option to true in a schema, the created model has properties with unknown types that will cause a lot of problems in implementing the application. However, when I switch back to version 6.7.5 the problem disappears.

Version 6.8.0:

(property) Users: Model<{
    createdAt: NativeDate;
    updatedAt: NativeDate;
} & {
    email?: unknown;
    password?: unknown;
    name?: unknown;
}, {}, {
    // This is a custom method in the schema
    comparePassword: (this: Document<unknown, any, FlatRecord<{
        email: string;
        password: string;
        name: string;
...

unknown-types-2

When switched back to version 6.7.5 without any modification:

(property) Users: Model<{
    email: string;
    password: string;
    name: string;
}, {}, {
    // This is a custom method in the schema
    comparePassword: (this: Document<unknown, any, FlatRecord<{
        email: string;
        password: string;
        name: string;
...

Steps to Reproduce

Considering you are using typescript:

  1. Install version 6.8.0 : npm i mongoose@6.8.0
  2. Create a schema with some properties and set the timestamps option to true.
  3. Create a connection using mongoose.createConnection.
  4. Create a model for the schema using the connection.model.
  5. Hover over the created model to see the type of the model.
const userSchema = new Schema(
  {
    email: {
      type: String,
      required: true,
    },

    password: {
      type: String,
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
  },
  {
    methods: {
      comparePassword: function (candidatePassword: string): Promise<boolean> {
        const user = this;

        return new Promise((resolve, reject) => {
          compare(candidatePassword, user.password, (err, isMatch) => {
            if (err) return reject(err);

            return resolve(isMatch);
          });
        });
      },
    },

    timestamps: true,
  }
);

const connection = createConnection(config.authDatabaseURL);

const Models = {
  Users: connection.model("users", userSchema),
};

Expected Behavior

(property) Users: Model<{
    createdAt: NativeDate;
    updatedAt: NativeDate;
} & {
    email: string;
    password: string;
    name: string;
}, {}, {
    // This is a custom method in the schema
    comparePassword: (this: Document<unknown, any, FlatRecord<{
        email: string;
        password: string;
        name: string;
...

Or:

(property) Users: Model<{
    email: string;
    password: string;
    name: string;
}, {}, {
    // This is a custom method in the schema
    comparePassword: (this: Document<unknown, any, FlatRecord<{
        email: string;
        password: string;
        name: string;
...
@Code-Mythos Code-Mythos changed the title unknown properties in schema when set timestams to true unknown properties in schema when set timestams to true in V6.8.0 Dec 16, 2022
@Code-Mythos Code-Mythos changed the title unknown properties in schema when set timestams to true in V6.8.0 unknown properties in schema when set timestams to true in v6.8.0 Dec 16, 2022
@Code-Mythos Code-Mythos changed the title unknown properties in schema when set timestams to true in v6.8.0 Unknown properties in the mongoose model when set timestams to true in v6.8.0 Dec 16, 2022
@IslandRhythms IslandRhythms added the can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. label Dec 16, 2022
@IslandRhythms
Copy link
Collaborator

image

import { Schema, model, connect, connection, createConnection } from 'mongoose';

// 1. Create an interface representing a document in MongoDB.
interface IUser {
  name: string;
  email: string;
  avatar?: string;
}

// 2. Create a Schema corresponding to the document interface.
const userSchema = new Schema<IUser>({
  name: { type: String, required: true },
  email: { type: String, required: true },
  avatar: String
}, { timestamps: true });

// 3. Create a Model.
// const User = model<IUser>('User', userSchema);

run().catch(err => console.log(err));

async function run() {
  // 4. Connect to MongoDB
  await createConnection('mongodb://localhost:27017/test');
  const User = connection.model<IUser>("User", userSchema);

  const user = new User({
    name: 'Bill',
    email: 'bill@initech.com',
    avatar: 'https://i.imgur.com/dM7Thhn.png'
  });
  await user.save();

  console.log(user.email); // 'bill@initech.com'
}

@Code-Mythos Code-Mythos changed the title Unknown properties in the mongoose model when set timestams to true in v6.8.0 Properties with unknown type in the mongoose model when set timestams to true in v6.8.0 Dec 16, 2022
@Code-Mythos
Copy link
Author

Code-Mythos commented Dec 16, 2022

unknown-types-2

Please try the following to reproduce the issue:

const userSchema = new Schema(
  {
    email: {
      type: String,
      required: true,
    },

    password: {
      type: String,
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
  },
  {
    methods: {
      comparePassword: function (candidatePassword: string): Promise<boolean> {
        const user = this;

        return new Promise((resolve, reject) => {
          compare(candidatePassword, user.password, (err, isMatch) => {
            if (err) return reject(err);

            return resolve(isMatch);
          });
        });
      },
    },

    timestamps: true,
  }
);

const connection = createConnection(config.authDatabaseURL);

const Models = {
  Users: connection.model("users", userSchema),
};

@IslandRhythms
Copy link
Collaborator

image
no change

@Code-Mythos
Copy link
Author

Code-Mythos commented Dec 16, 2022

I've attached an image to my previous comment.
When you create a user by defining all its required fields it's obvious that there will not be an error.
*** Please hover over "Users" in the Models object. ***

Further:
Consider when you found a user using the findOne method and then you are trying to use the comparePassword method:

unknown-types-3

          const user = await Db.Users.findOne({ email });

          if (!user) throw new Error(`User not found: ${email}`);

          // Ignore typescript error
          const isPasswordValid: boolean = await user.comparePassword(password);

          if (!isPasswordValid) throw new Error(`Invalid password: ${email}`);

          // Any object returned will be saved in `user` property of the JWT
          const userObject: User = {
            id: user._id.toString(),
            name: user.name,
            email: user.email,
          };

          return userObject;

@IslandRhythms IslandRhythms changed the title Properties with unknown type in the mongoose model when set timestams to true in v6.8.0 Properties with unknown type in the mongoose model when set timestamps to true in v6.8.0 Dec 16, 2022
@IslandRhythms
Copy link
Collaborator

image
My b

@IslandRhythms IslandRhythms added typescript Types or Types-test related issue / Pull Request and removed can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. labels Dec 16, 2022
@Code-Mythos
Copy link
Author

Code-Mythos commented Dec 16, 2022

When you switch back to v6.7.5 the problem disappears.
I do not know what happens to the type definitions in v6.8.0 when the timestamps option is set to true.
Thank you for your follow-up.

@vkarpov15 vkarpov15 added this to the 6.8.3 milestone Dec 29, 2022
@vkarpov15
Copy link
Collaborator

Confirmed that the following script fails to compile due to gh-12807.ts:46:9 - error TS2322: Type 'unknown' is not assignable to type 'string'.

import { Schema, createConnection } from 'mongoose';

const userSchema = new Schema(
  {
    email: {
      type: String,
      required: true,
    },

    password: {
      type: String,
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
  },
  {
    methods: {
      comparePassword: function (candidatePassword: string): Promise<boolean> {
        const user = this;

        return new Promise((resolve, reject) => {
          resolve(true);
        });
      },
    },

    timestamps: true,
  }
);

const connection = createConnection('mongodb://localhost:27017/test');

const Models = {
  Users: connection.model("users", userSchema),
};

const user = new Models.Users({ name: 'foo', password: 'bar', email: 'baz' });

const name: string = user.name;

async function foo() {
  const user = await Models.Users.findOne().orFail();
  const name: string = user.name;
}

@vkarpov15
Copy link
Collaborator

I haven't been able to fix this issue yet, but I found an ok workaround using as:

const userSchema = new Schema(
  {
    email: {
      type: String,
      required: true,
    },

    password: {
      type: String,
      required: true,
    },
    name: { 
      type: String,
      required: true,
    },
  },
  { 
    methods: {
      comparePassword: function (candidatePassword: string): Promise<boolean> {
        const user = this;

        return new Promise((resolve, reject) => {
          resolve(true);
        });
      },
    },

    timestamps: true,
  } as { timestamps: true, methods: any } // <-- I guess this is enough to convince TS that `timestamps` is actually true?
);

@Code-Mythos can you confirm whether this as trick works for you?

@Code-Mythos
Copy link
Author

@vkarpov15 Thank you for your reply.
No, it does not work for me:

mongoose3

vkarpov15 added a commit that referenced this issue Jan 6, 2023
fix(types): avoid inferring timestamps if `methods`, `virtuals`, or `statics` set
@vkarpov15 vkarpov15 modified the milestones: 6.8.3, 6.8.5 Jan 6, 2023
@vkarpov15 vkarpov15 modified the milestones: 6.8.5, 6.8.6 Jan 23, 2023
@vkarpov15 vkarpov15 modified the milestones: 6.9.1, 6.9.3, TypeScript backlog Feb 4, 2023
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

No branches or pull requests

3 participants