I try to create method hashPassword for user schema.
schema.method("hashPassword", function (): void {
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(this.password, salt);
this.password = hash;
});
And get an error Property 'password' does not exist on type 'Document<any>'. on password
Here is my file
import mongoose, { Schema, Document } from "mongoose";
import bcrypt from "bcryptjs";
/**
* This interface should be the same as JWTPayload declared in types/global.d.ts file
*/
export interface IUser extends Document {
name: string;
email: string;
username: string;
password: string;
confirmed: boolean;
hashPassword: () => void;
checkPassword: (password: string) => boolean;
}
// User schema
const schema = new Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
confirmed: {
type: Boolean,
default: false,
},
},
{ timestamps: true }
);
schema.method("hashPassword", function (): void {
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(this.password, salt);
this.password = hash;
});
// User model
export const User = mongoose.model<IUser>("User", schema, "users");
At the point where you define the method, the schema object doesn't know that it is the Schema for an IUser and not just any Document. You need to set the generic type for the Schema when you create it: new Schema<IUser>( ... ).
As suggested by one of the collaborators of mongoose, we can use the below way for creating instance methods:
const schema = new Schema<ITestModel, Model<ITestModel, {}, InstanceMethods>> // InstanceMethods would be the interface on which we would define the methods
schema.methods.methodName = function() {}
const Model = model<ITestModel, Model<ITestModel, {}, InstanceMethods>>("testModel", ModelSchema)
const modelInstance = new Model();
modelInstance.methodName() // works
link: https://github.com/Automattic/mongoose/issues/10358#issuecomment-861779692
You should declare an interface that extends Model like so:
interface IUser {...}
interface IUserInstanceCreation extends Model<IUser> {}
then declare your schema;
const userSchema = new Schema<IUser, IUserInstanceCreation, IUser>({...})
This would as well ensure that the Schema follows the attributes in IUser.