J'essaie actuellement d'ajouter une méthode statique à mon schéma mangouste, mais je ne trouve pas la raison pour laquelle cela ne fonctionne pas de cette façon.
Mon modele:
import * as bcrypt from 'bcryptjs';
import { Document, Schema, Model, model } from 'mongoose';
import { IUser } from '../interfaces/IUser';
export interface IUserModel extends IUser, Document {
comparePassword(password: string): boolean;
}
export const userSchema: Schema = new Schema({
email: { type: String, index: { unique: true }, required: true },
name: { type: String, index: { unique: true }, required: true },
password: { type: String, required: true }
});
userSchema.method('comparePassword', function (password: string): boolean {
if (bcrypt.compareSync(password, this.password)) return true;
return false;
});
userSchema.static('hashPassword', (password: string): string => {
return bcrypt.hashSync(password);
});
export const User: Model<IUserModel> = model<IUserModel>('User', userSchema);
export default User;
IUser:
export interface IUser {
email: string;
name: string;
password: string;
}
Si j'essaie maintenant d'appeler User.hashPassword(password)
, je reçois l'erreur suivante [ts] Property 'hashPassword' does not exist on type 'Model<IUserModel>'.
Je sais que je n'ai défini la méthode nulle part, mais je ne sais pas vraiment où la mettre, car je ne peux pas mettre une méthode statique dans une interface . Merci d'avance!
Je pense que vous rencontrez le même problème que je viens de lutter. Ce problème est dans votre appel. Plusieurs tutoriels vous ont appelé la méthode .comparePassword()
à partir du modèle comme celui-ci.
User.comparePassword(candidate, cb...)
Cela ne fonctionne pas car la méthode est sur la schema
et non sur la model
. La seule façon pour moi d’appeler cette méthode a été de trouver cette instance du modèle à l’aide des méthodes standard d’interrogation Mangouste/Mongo.
Voici une partie pertinente de mon middleware de passeport:
passport.use(
new LocalStrategy({
usernameField: 'email'
},
function (email: string, password: string, done: any) {
User.findOne({ email: email }, function (err: Error, user: IUserModel) {
if (err) throw err;
if (!user) return done(null, false, { msg: 'unknown User' });
user.schema.methods.comparePassword(password, user.password, function (error: Error, isMatch: boolean) {
if (error) throw error;
if (!isMatch) return done(null, false, { msg: 'Invalid password' });
else {
console.log('it was a match'); // lost my $HÏT when I saw it
return done(null, user);
}
})
})
})
);
J'ai donc utilisé findOne({})
pour obtenir l'instance de document, puis j'ai dû accéder aux méthodes de schéma en fouillant dans les propriétés de schéma du document user.schema.methods.comparePassword
.
Quelques différences que j'ai remarquées:
instance
alors que la vôtre est une méthode static
. Je suis convaincu qu'il existe une stratégie similaire d'accès aux méthodes.comparePassword()
. peut-être que ce n'est pas nécessaire en statique, mais je n'ai pas pu accéder à this.password
J'avais le même problème que vous, et j'ai finalement réussi à le résoudre après avoir lu la documentation dans les typages de mangouste TS (que je ne connaissais pas auparavant, et je ne sais pas depuis combien de temps les docs sont là), spécifiquement cette section . Je comprends que c’est une très vieille question, mais j’ai pensé que cela pourrait aider une personne perdue à l’avenir. _ {Edit: je lis la date d'une réponse existante comme mars 2014, pas comme le 14 mars.} _
En ce qui concerne votre cas, vous voudrez suivre un schéma similaire à celui que vous avez actuellement, bien que vous deviez changer quelques choses dans les deux fichiers.
Fichier IUser
IUser
en IUserDocument
. Cela permet de séparer votre schéma de vos méthodes d'instance.Document
à partir de mangouste.Document
.Fichier modèle
IUser
en IUserDocument
, y compris le chemin du module si vous renommez le fichier.IUserModel
en IUser
.IUser
s'étend de, de IUserDocument, Document
à IUserDocument
.IUserModel
qui s'étend de Model<IUser>
.IUserModel
.User
de Model<IUserModel>
en IUserModel
, car IUserModel
étend maintenant Model<IUser>
.<IUserModel>
à <IUser, IUserModel>
.Voici à quoi ressemblerait votre fichier de modèle avec ces modifications:
import * as bcrypt from 'bcryptjs';
import { Document, Schema, Model, model } from 'mongoose';
import { IUserDocument } from '../interfaces/IUserDocument';
export interface IUser extends IUserDocument {
comparePassword(password: string): boolean;
}
export interface IUserModel extends Model<IUser> {
hashPassword(password: string): boolean;
}
export const userSchema: Schema = new Schema({
email: { type: String, index: { unique: true }, required: true },
name: { type: String, index: { unique: true }, required: true },
password: { type: String, required: true }
});
userSchema.method('comparePassword', function (password: string): boolean {
if (bcrypt.compareSync(password, this.password)) return true;
return false;
});
userSchema.static('hashPassword', (password: string): string => {
return bcrypt.hashSync(password);
});
export const User: IUserModel = model<IUser, IUserModel>('User', userSchema);
export default User;
Et votre module (nouvellement renommé) ../interfaces/IUserDocument
ressemblerait à ceci:
import { Document } from 'mongoose';
export interface IUserDocument extends Document {
email: string;
name: string;
password: string;
}
Pour les futurs lecteurs:
N'oubliez pas que nous traitons de deux concepts mongo/mangouste différents: un modèle et des documents.
De nombreux documents peuvent être créés à partir d'un seul modèle. Le modèle est le modèle, le document est la chose créée conformément aux instructions du modèle.
Chaque document contient ses propres données. Chacun comporte également ses propres méthodes d'instance, liées à sa propre variable this
et ne fonctionnant que sur cette instance spécifique.
Le modèle peut avoir des méthodes «statiques» qui ne sont pas liées à une instance de document spécifique, mais fonctionnent sur toute la collection de documents.
Comment tout cela se rapporte à TypeScript:
.method
..static
.Les autres réponses ici ont un code correct, regardez-les et tracez les différences entre la manière dont les documents sont définis et celle des modèles.
Et rappelez-vous que lorsque vous utilisez ces éléments dans votre code, le modèle sert à créer de nouveaux documents et à appeler des méthodes statiques telles que User.findOne
ou votre statique personnalisée (comme User.hashPassword
est défini ci-dessus).
Et les documents sont ce que vous utilisez pour accéder aux données spécifiques de l'objet ou pour appeler des méthodes d'instance comme this.save
et des méthodes d'instance personnalisées comme this.comparePassword
définies ci-dessus.
Je ne vois pas votre interface IUser, mais je soupçonne que vous n’avez pas inclus les méthodes ici
export interface IUser {
email: string,
hash: string,
salt: string,
setPassword(password: string): void,
validPassword(password: string): boolean,
generateJwt(): string
}
TypeScript reconnaîtra alors vos méthodes et cessera de se plaindre