web-dev-qa-db-fra.com

Méthode de modèle statique de type mangouste typescript "La propriété n'existe pas sur le type"

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!

17
Cludch

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:

  1. La mienne est une méthode 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.
  2. J'ai trouvé que je devais passer le hachage à la fonction comparePassword(). peut-être que ce n'est pas nécessaire en statique, mais je n'ai pas pu accéder à this.password
10
Nate May

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 sectionJe 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

  1. Renommez IUser en IUserDocument. Cela permet de séparer votre schéma de vos méthodes d'instance.
  2. Importer Document à partir de mangouste.
  3. Étendre l'interface à partir de Document.

Fichier modèle

  1. Renommez toutes les instances de IUser en IUserDocument, y compris le chemin du module si vous renommez le fichier.
  2. Renommez uniquement la définition de IUserModel en IUser.
  3. Modifier ce que IUser s'étend de, de IUserDocument, Document à IUserDocument.
  4. Créez une nouvelle interface appelée IUserModel qui s'étend de Model<IUser>.
  5. Déclarez vos méthodes statiques dans IUserModel.
  6. Changez le type de constante User de Model<IUserModel> en IUserModel, car IUserModel étend maintenant Model<IUser>.
  7. Modifiez l'argument de type de votre appel de modèle de <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;
}
30
Harry Shipton

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: 

  • Étendre le document pour définir des types pour les propriétés d'instance et les fonctions .method.
  • Développez le modèle (d'un document) pour définir des types pour les fonctions .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.

3
Max Wilder

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

0
xerotolerant