Answer a question

-- userSchema.ts interface

import mongoose, { Schema, Document } from "mongoose";
import moment from "moment";
import bcrypt from "bcrypt";

export interface UserDoc extends Document {
  name: {
    type: string;
    required: boolean;
  };
  email: {
    type: string;
    required: boolean;
  };
  password: {
    type: string;
    required: boolean;
  };
  dateJoined: {
    type: string;
    default: string;
  };
}

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

  dateJoined: {
    type: String,
    default: moment().format("MMMM Do YYYY"),
  },
});

I created my user model and the problem I'm having is creating the matchPassword method with uses bcrypt to compare the enteredPassword parameter vs the password from the Database

userSchema.methods.matchPassword = async function (enteredPassword) {
  return await bcrypt.compare(enteredPassword, this.password); ***
};

userSchema.pre("save", async function (next) {
  if (this.isModified("password")) {
    next();
  }

  const salt = bcrypt.genSalt(10);

  *** this.password = await bcrypt.hash(this.password, await salt); ***
});

const User = mongoose.model("User", userSchema);

The error message is as follows:

Property 'password' does not exist on type 'Document<any>'.

and this error is on each instance of this.password highlighted by the ***

I have used this same method before in Javascript so I do not know why It doesn't work on typescript and how can I bind the this.password to the Mongoose Document

Thank you

Answers

It looks like @Mohammad has helped you with the bcrypt implementation. I can help you with the typescript errors!

UserDoc is a typescript interface, so it shouldn't have fields like required. It should just describe the type of a UserDoc object. Properties are required by default. We use ?: if they are optional, but it looks like all are required here.

export interface UserDoc extends Document {
  name: string;
  email: string;
  password: string;
  dateJoined: string;
  matchPassword: (pw: string) => Promise<boolean>
}

When you create userSchema, you tell typescript that this is the schema for a UserDoc - not just any Document - by setting the generic variable of the Schema constructor to UserDoc.

const userSchema = new Schema<UserDoc>({ ...

This clears up the errors in userSchema.methods.matchPassword since we know that this.password is a string. We also know that enteredPassword is a string because we defined the args for this matchPassword method in the UserDoc interface.

For some reason, the pre method doesn't know our document type automatically. But the pre method is itself a generic function, so we can specific again that our doc is a UserDoc.

userSchema.pre<UserDoc>( ...

This is dumb but we have to specify the generic again when we create the model.

const User = mongoose.model<UserDoc>("User", userSchema);

Now User has type mongoose.Model<UserDoc, {}> and any methods that you call should return a UserDoc instead of just a Document.

Logo

MongoDB社区为您提供最前沿的新闻资讯和知识内容

更多推荐