简体   繁体   English

使用 TypeScript 创建 mongoose 模式方法

[英]Create mongoose schema methods using TypeScript

I try to create method hashPassword for user schema.我尝试为用户模式创建方法 hashPassword。

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>'.并得到一个错误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 .在定义方法时, schema object 不知道它是IUserSchema而不仅仅是任何Document You need to set the generic type for the Schema when you create it: new Schema<IUser>(... ) .创建Schema时需要为它设置泛型类型: new Schema<IUser>(... )

You should declare an interface that extends Model like so:您应该声明一个扩展 Model 的接口,如下所示:

    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.这也将确保 Schema 遵循 IUser 中的属性。

As suggested by one of the collaborators of mongoose, we can use the below way for creating instance methods:正如 mongoose 的一位合作者所建议的,我们可以使用以下方式来创建实例方法:

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链接: https://github.com/Automattic/mongoose/issues/10358#issuecomment-861779692

This makes is Clear Enough这很清楚

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

interface IUser {
    username: string;
    hashedPassword: string;
}

interface IUserDocument extends IUser, Document {
    setPassword: (password: string) => Promise<void>;
    checkPassword: (password: string) => Promise<boolean>;
}

interface IUserModel extends Model<IUserDocument> {
    findByUsername: (username: string) => Promise<IUserDocument>;
}

const UserSchema: Schema<IUserDocument> = new Schema({
    username: { type: String, required: true },
    hashedPassword: { type: String, required: true },
});

UserSchema.methods.setPassword = async function (password: string) {
    const hash = await bcrypt.hash(password, 10);
    this.hashedPassword = hash;
};

UserSchema.methods.checkPassword = async function (password: string) {
    const result = await bcrypt.compare(password, this.hashedPassword);
    return result;
};

UserSchema.statics.findByUsername = function (username: string) {
    return this.findOne({ username });
};

const User = mongoose.model<IUserDocument, IUserModel>("User", UserSchema);
export default User;

Solution to avoid having to redefine types that are already in the schema避免必须重新定义模式中已经存在的类型的解决方案

import { Schema, model, InferSchemaType } from "mongoose"
import bcrypt from "bcrypt"

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

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

declare interface IUser extends InferSchemaType<typeof userSchema> {
    verifyPassword(password: string): boolean
}

export const UserModel = model<IUser>("Users", userSchema)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM