Not able to access a mongoose schema's method

24 views Asked by At

I am trying to access the schema methods of mongoose schema but getting an error. (Working in typescript)

Schema

const userSchema: Schema<IUser> = new Schema(
  {
    name: {
      type: String,
      required: [true, "Name is required"],
      maxLength: [50, "Name should be smaller than 50 characters"],
      lowercase: true,
      trim: true,
    },
    password: {
      type: String,
      required: [true, "Password is required"],
      select: false,
      minLength: [8, "Password must be at least 8 characters"],
    },
// ...other props
);

Schema Methods

userSchema.methods = {
  comparePassword: async function (plainTextPassword: string) {
    return await bcrypt.compare(plainTextPassword, this.password);
  },
};

Usage

const user = await User.findOne({ email }).select("+password");
let isPassCorrect;
if (user) isPassCorrect = await user.comparePassword(password);

Here I am getting an error that

Property 'comparePassword' does not exist on type 'Document<unknown, {}, IUser> & IUser & Required<{ _id: ObjectId; }>'.

I've tried to make statics instead of schemas but it's also giving an error.

Any help would be appreciated... Thanks in advance.

1

There are 1 answers

0
sxeros On BEST ANSWER

The error you're experiencing is due to TypeScript not recognizing your comparePassword method as part of the IUser interface, which is used to type your mongoose model. In Mongoose, methods added to a schema are not automatically recognized by TypeScript. You need to explicitly declare them in an interface to make TypeScript aware of these custom schema methods.

To resolve this, you should extend the Document type with an interface that includes your custom methods. Here's how you can do it:

  1. First, define an interface for your custom methods. This interface should extend from mongoose.Document and include your custom method signatures. Assuming IUser is your original interface for the user schema, you'll create another interface for the schema methods:
import { Document } from 'mongoose';

interface IUserMethods extends Document {
  comparePassword: (plainTextPassword: string) => Promise<boolean>;
}
  1. When you create the model, use this extended interface (IUserMethods) as the document type. This way, TypeScript will know about your custom methods. Here's how you modify the Schema and model creation:
import mongoose, { Schema } from 'mongoose';
import bcrypt from 'bcrypt';

// Assuming IUser is your original interface for user attributes
interface IUser {
  name: string;
  password: string;
  // Add other properties here
}

// New interface for methods
interface IUserMethods extends Document {
  comparePassword: (plainTextPassword: string) => Promise<boolean>;
}

const userSchema: Schema<IUser> = new Schema({
  // Schema definition remains the same
});

// Define methods
userSchema.methods.comparePassword = async function (this: IUserMethods, plainTextPassword: string): Promise<boolean> {
  return bcrypt.compare(plainTextPassword, this.password);
};

// Create the model
const User = mongoose.model<IUserMethods>('User', userSchema);

This approach informs TypeScript about the custom methods (comparePassword in this case) you've added to the schema, resolving the error you encountered. Now, when you use your User model, TypeScript will recognize the comparePassword method and type check its usage accordingly.

Remember, every time you add a new method to your schema that you intend to use in your TypeScript code, you'll need to extend your interface to include those method signatures to keep TypeScript aware of these custom methods.