Создание методов схемы мангуста с использованием TypeScript

#node.js #typescript #mongoose

#node.js #машинописный текст #мангуст

Вопрос:

Я пытаюсь создать метод HashPassword для схемы пользователя.

 schema.method("hashPassword", function (): void {
  const salt = bcrypt.genSaltSync(10);
  const hash = bcrypt.hashSync(this.password, salt);

  this.password = hash;
});
 

И получите сообщение об ошибке Property 'password' does not exist on type 'Document<any>'. при вводе пароля

Вот мой файл

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

 

Ответ №1:

В момент, когда вы определяете метод, schema объект не знает, что это Schema for an IUser , а не просто any Document . Вам необходимо установить общий тип для Schema при его создании : new Schema<IUser>( ... ) .

Комментарии:

1. Намного проще, чем другие ответы.

Ответ №2:

Как предложил один из сотрудников 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
 

ссылка: https://github.com/Automattic/mongoose/issues/10358#issuecomment-861779692

Ответ №3:

Вы должны объявить интерфейс, который расширяет модель следующим образом:

     interface IUser {...}
    interface IUserInstanceCreation extends Model<IUser> {}
 

затем объявите свою схему;

     const userSchema = new Schema<IUser, IUserInstanceCreation, IUser>({...})
 

Это также гарантировало бы, что Схема соответствует атрибутам в IUser.

Комментарии:

1. Я уже понял это, но все равно спасибо

Ответ №4:

Это делает достаточно понятным

 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 resu<
};

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

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