mongoose 属性 'password' 在类型 'Document<any> 上不存在

mongoose property 'password' does not exist on type 'Document<any>

-- userSchema.ts 界面

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"),
  },
});

我创建了我的用户模型,我遇到的问题是创建 matchPassword 方法并使用 bcrypt 比较 enteredPassword 参数与数据库中的密码

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);

报错信息如下:

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

并且此错误出现在由 ***

突出显示的 this.password 的每个实例上

我之前在 Javascript 中使用过同样的方法,所以我不知道为什么它在打字稿上不起作用,我该如何绑定 this.password到猫鼬文档

谢谢

不要在 return 中使用 await,所以只需尝试

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

并且你不需要在 bcrypt 中加入盐,之后第二个参数应该是一个数字

this.password = await bcrypt.hash(this.password, 12);

基于documentation如果你想使用盐你可以这样做

const bcrypt = require('bcrypt');
const saltRounds = 10;
const myPlaintextPassword = 's0/\/\P4$$w0rD';
const someOtherPlaintextPassword = 'not_bacon';


const salt = bcrypt.genSaltSync(saltRounds);
const hash = bcrypt.hashSync(myPlaintextPassword, salt);

看起来@Mohammad 已帮助您完成 bcrypt 实施。我可以帮助您解决打字稿错误!

UserDoc 是一个 typescript 接口,所以它不应该有像 required 这样的字段。它应该只描述 UserDoc 对象的类型。默认情况下需要属性。如果它们是可选的,我们使用 ?:,但看起来这里都是必需的。

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

当你创建 userSchema 时,你通过设置 Schema 构造函数到 UserDoc.

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

这清除了 userSchema.methods.matchPassword 中的错误,因为我们知道 this.passwordstring。我们也知道 enteredPassword 是一个 string 因为我们在 UserDoc 接口中为这个 matchPassword 方法定义了参数。

出于某种原因,pre 方法无法自动识别我们的文档类型。但是 pre 方法本身是一个通用函数,所以我们可以再次指定我们的文档是 UserDoc.

userSchema.pre<UserDoc>( ...

这很愚蠢,但我们必须在创建模型时再次指定通用

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

现在 User 的类型为 mongoose.Model<UserDoc, {}> 并且您调用的任何方法都应该 return 一个 UserDoc 而不仅仅是一个 Document.