简体   繁体   中英

Mongoose loadClass issue with TypeScript

I'm taking advantage of mongoose class schemas .

And using TypeScript for my Node project.

I've followed Mongoose the Typescript way...? to make sure my Model is aware of the schema I've defined, So I've auto-completion etc..

However it becomes more tricky with schema class. As written in their docs:

The loadClass() function lets you pull in methods, statics, and virtuals from an ES6 class. A class method maps to a schema method, a static method maps to a schema static, and getters/setters map to virtuals.

So my code looks something like:

interface IUser extends mongoose.Document {
  firstName: string,
  lastName: string
};

const userSchema = new mongoose.Schema({
  firstName: {type:String, required: true},
  lastName: {type:String, required: true},
});

class UserClass{
   static allUsersStartingWithLetter(letter: string){
       return this.find({...});
   }
   fullName(this: IUser){
      return `${this.firstName} ${this.lastName}`
   }
}
userSchema.loadClass(UserClass);

const User = mongoose.model<IUser>('User', userSchema);
export default User;

My goal is that TypeScript will understand that:

  1. User has a method allUsersStartingWithLetter
  2. User instance has a method fullName

In the current configuration it does not. I was not able to accomplish it myself.

Do you really need to use classes? I could accomplish this using interfaces without using classes to do it. Here's an example:

/* eslint-disable func-names */
import mongoose from 'mongoose';
export interface Foo {
  id?: string;
  name: string;
  createdAt?: Date;
  updatedAt?: Date;
}

export type FooDocument = mongoose.Document & Foo;

const fooSchema = new mongoose.Schema(
  {
    name: { type: String, required: true },
  },
  { timestamps: true }
);

fooSchema.methods.bar = function (): void {
  const foo = this as FooDocument;
  foo.name = 'bar';
};

const FooModel = mongoose.model<FooDocument>('foos', fooSchema);

export default FooModel;

This way you can use the Foo interface for methods with the inversion depedency. Them in your repository will return Foo instead of FooDocument...

Extra: If you use lean() in your database requests you return exactly the Foo interface. More information for lean here

Have you considered adding extends mongoose.Model to the UserClass ?

class UserClass extends mongoose.Model<IUser> {
   static allUsersStartingWithLetter(letter: string){
       return this.find({...});
   }
   fullName(this: IUser){
      return `${this.firstName} ${this.lastName}`
   }
}

Your UserClass needs to extend Model from mongoose . You seem to be missing a bit of required code to make this work for you.

From the link you shared as a reference, here's a guide that should solve your issue with complete code example.

https://stackoverflow.com/a/58107396/1919397

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM