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