node.js - نمیتوان به context اسکیمای mongoose در Typescript دسترسی پیدا کرد
من سعی دارم توابع .pre، .method و .static را روی شِماهای Mongoose خود اعمال کنم.
من کد زیر را دارم، اما this من یا در زمینه اشتباه است یا من Schemas را اشتباه متوجه شدهام.
export interface IUser extends mongoose.Document {
email: string;
password: string;
firstName: string;
lastName: string;
comparePassword(password: string, callback: Function): void;
}
class UserSchema {
static get schema(): mongoose.Schema {
let userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
lowercase: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
password: {
type: String,
select: false
}
});
userSchema.pre('save', this.saveHandler);
userSchema.method('comparePassword', this.comparePassword);
return userSchema;
}
static saveHandler(next) {
let user = this.schema;
if(!user.isModified('password')) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
next();
});
});
}
static comparePassword(password: string, callback: Function) {
let user = this.schema;
bcrypt.compare(password, user.password, (err, isMatch) => {
callback(err, isMatch);
});
}
}
export const UserModel = mongoose.model<IUser>('User', UserSchema.schema);
تایپاسکریپت خطاهایی ایجاد میکند که Property 'isModified' does not exist on type 'Schema'.
با این حال، در جاوااسکریپت:
var schema = new Schema({
email: { type: String, unique: true, lowercase: true },
password: { type: String, select: false },
firstName: String,
lastName: String,
});
schema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) {
return next();
}
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
user.password = hash;
next();
});
});
});
واقعاً دارای بافت صحیح this است. چگونه میتوانم کد تایپاسکریپت خود را بهدرستی ساختاربندی کنم تا همان اثر را داشته باشد؟
پاسخ شماره ۱
مشکل اینجا این است که مقدار این داخل متدهای ایستا است. این کد اصلی شماست.
class UserSchema {
static get schema(): mongoose.Schema {
let userSchema = new mongoose.Schema({ ... });
// this does not refer to UserSchema!
userSchema.pre('save', this.saveHandler);
userSchema.method('comparePassword', this.comparePassword);
return userSchema;
}
static saveHandler(next) {
...
}
static comparePassword(password: string, callback: Function) {
...
}
}
پس، یک رویکرد اولیه میتواند تغییر کلیدواژه this با ارجاع UserSchema باشد
class UserSchema {
static get schema(): mongoose.Schema {
let userSchema = new mongoose.Schema({ ... })
userSchema.pre('save', UserSchema.saveHandler);
userSchema.method('comparePassword', UserSchema.comparePassword);
return userSchema;
}
static saveHandler(next) {
let user = UserSchema.schema;
...
}
static comparePassword(password: string, callback: Function) {
...
}
}
اما، همانطور که @toskv گفت، من توصیه میکنم از متدهای استاتیک استفاده نکنید. تایپاسکریپت پیشرفتی بسیار بزرگ نسبت به جاوااسکریپت است اما فکر نکنید که مانند جاوا است. از یک طراحی مبتنی بر ماژول استفاده کنید.
برای مثال میتوانید ماژول userSchema.ts را به عنوان قالب زیر تعریف کنید:
// private to the module
const _schema = new mongoose.Schema({ ... })
_schema.pre('save', _saveHandler)
_schema.method('comparePassword', _comparePassword)
/** from the outside you'll call it as
*
* const userSchema = require('...')
* userSchema.getSchema()
*/
export function getSchema() {
return _schema
}
// private to the module
function _saveHandler(next: Function) {
...
}
// private to the module
function _comparePassword(next: Function) {
...
}
پاسخ شماره ۲
استفاده از تابع بدون تابع پیکانی همانطور که فدورانیموس گفت عمل میکند
