【问题标题】:mongoose property 'password' does not exist on type 'Document<any>'Document<any> 类型上不存在猫鼬属性'密码'
【发布时间】:2021-05-09 04:24:39
【问题描述】:

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

我创建了我的用户模型,我遇到的问题是创建 ma​​tchPassword 方法并使用 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 中使用过同样的方法,所以我不知道为什么它在 typescript 上不起作用以及如何将 this.password 绑定到 Mongoose 文档

谢谢

【问题讨论】:

    标签: node.js mongodb typescript mongoose bcrypt


    【解决方案1】:

    不要使用 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);
    

    【讨论】:

      【解决方案2】:

      看起来@Mohammad 帮助您实现了bcrypt。我可以帮你解决打字稿错误!

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

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

      当您创建 userSchema 时,您通过将 Schema 构造函数的泛型变量设置为 UserDoc 来告诉 typescript 这是 UserDoc 的架构 - 而不仅仅是任何 Document

      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&lt;UserDoc, {}&gt; 类型,您调用的任何方法都应返回UserDoc 而不仅仅是Document

      【讨论】:

      • 谢谢。我是 Typescript 的新手,所以接口有点混乱。这对我有用!
      猜你喜欢
      • 2021-09-10
      • 2021-05-04
      • 2017-07-05
      • 2021-02-08
      • 2019-09-20
      • 2018-09-09
      • 2019-12-31
      • 1970-01-01
      • 2022-12-17
      相关资源
      最近更新 更多