Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
750 views
in Technique[技术] by (71.8m points)

node.js - Typescript mongoose static model method "Property does not exist on type"

I am currently trying to add a static method to my mongoose schema but I can't find the reason why it doesn't work this way.

My model:

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

If I now try to call User.hashPassword(password) I am getting the following error [ts] Property 'hashPassword' does not exist on type 'Model<IUserModel>'.

I know that I didn't define the method anywhere but I don't really know where I could put it as I can't just put a static method into an interface. I hope you can help my find the error, thanks in advance!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I was having the same problem as you, and then finally managed to resolve it after reading the documentation in the TS mongoose typings (which I didn't know about before, and I'm not sure how long the docs have been around), specifically this section.


As for your case, you'll want to follow a similar pattern to what you currently have, although you'll need to change a few things in both files.

IUser file

  1. Rename IUser to IUserDocument. This is to separate your schema from your instance methods.
  2. Import Document from mongoose.
  3. Extend the interface from Document.

Model file

  1. Rename all instances of IUser to IUserDocument, including the module path if you rename the file.
  2. Rename only the definition of IUserModel to IUser.
  3. Change what IUser extends from, from IUserDocument, Document to IUserDocument.
  4. Create a new interface called IUserModel which extends from Model<IUser>.
  5. Declare your static methods in IUserModel.
  6. Change the User constant type from Model<IUserModel> to IUserModel, as IUserModel now extends Model<IUser>.
  7. Change the type argument on your model call from <IUserModel> to <IUser, IUserModel>.

Here's what your model file would look like with those changes:

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): string;
}

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;

And your (newly renamed) ../interfaces/IUserDocument module would look like this:

import { Document } from 'mongoose';

export interface IUserDocument extends Document {
    email: string;
    name: string;
    password: string;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...