使用TypeScript创建mongoose架构方法



我尝试为用户模式创建方法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");

在定义方法时,schema对象不知道它是IUserSchema,而不仅仅是任何Document。创建Schema时,需要为其设置通用类型:new Schema<IUser>( ... )

正如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

这使得足够清晰

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;

您应该声明一个扩展Model的接口,如下所示:

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

然后声明你的模式;

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

这还可以确保Schema遵循IUser中的属性。

避免重新定义模式中已经存在的类型的解决方案

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)

最新更新