Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose static Model definitions in Typescript

I created a Mongoose Schema and added some static methods for the Model, named Campaign.

If I console.log Campaign I can see the methods present on it. The problem is I don't know where to add those methods so that Typescript is also aware of them.

If I add them to my CampaignModelInterface, they are only available for instances of the model (or at least TS thinks they are).

campaignSchema.ts

  export interface CampaignModelInterface extends CampaignInterface, Document {
      // will only show on model instance
  }

  export const CampaignSchema = new Schema({
      title: { type: String, required: true },
      titleId: { type: String, required: true }
      ...etc
  )}

  CampaignSchema.statics.getLiveCampaigns = Promise.method(function (){
      const now: Date = new Date()
      return this.find({
           $and: [{startDate: {$lte: now} }, {endDate: {$gte: now} }]
      }).exec()
  })

  const Campaign = mongoose.model<CampaignModelInterface>('Campaign', CampaignSchema)
  export default Campaign

I also tried accessing it via Campaign.schema.statics, but without luck.

Can anyone advise how to let TS know about the methods present on the Model, not the Model instances?

like image 921
Daniel Nitu Avatar asked Aug 10 '17 12:08

Daniel Nitu


People also ask

Can Mongoose be used with TypeScript?

Mongoose introduced officially supported TypeScript bindings in v5. 11.0. Mongoose's index.

What is static method in mongoose?

statics are the methods defined on the Model. methods are defined on the document (instance). You might use a static method like Animal.findByName : const fido = await Animal. findByName('fido'); // fido => { name: 'fido', type: 'dog' }

What defines a data model in mongoose?

Mongoose models A model is a compiled version of the schema. One instance of the model will map to one document in the database. Creating a User instance based on the schema userSchema is a one line task: var User = mongoose.model('User', userSchema); Copy.

What is the difference between statics and methods in mongoose?

Methods operate on an instance of a model. Statics behave as helper functions only and can perform any action you want, including collection level searching. They aren't tied to an instance of a Model. But methods are also defined on models and work on all the instances of that model.


1 Answers

I answered a very similar question over here, although I'll answer yours (mostly with the third section of my other answer) as you've provided a different schema. There is a helpful readme with the Mongoose typings which is fairly hidden away, but there's a section on static methods.


The behaviour that you described is perfectly normal - Typescript is being told that the Schema (the object which describes individual documents) has the method called getLiveCampaigns.

Instead, you need to tell Typescript that the method is on the model, not the schema. Once done, you can access static methods as per the normal Mongoose method. You can do that by the following:

// CampaignDocumentInterface should contain your schema interface,
// and should extend Document from mongoose.
export interface CampaignInterface extends CampaignDocumentInterface {
    // declare any instance methods here
}

// Model is from mongoose.Model
interface CampaignModelInterface extends Model<CampaignInterface> {
    // declare any static methods here
    getLiveCampaigns(): any; // this should be changed to the correct return type if possible.
}

export const CampaignSchema = new Schema({
    title: { type: String, required: true },
    titleId: { type: String, required: true }
    // ...etc
)}

CampaignSchema.statics.getLiveCampaigns = Promise.method(function (){
    const now: Date = new Date()
    return this.find({
        $and: [{startDate: {$lte: now} }, {endDate: {$gte: now} }]
    }).exec()
})

// Note the type on the variable, and the two type arguments (instead of one).
const Campaign: CampaignModelInterface = mongoose.model<CampaignInterface, CampaignModelInterface>('Campaign', CampaignSchema)
export default Campaign
like image 183
Matt Shipton Avatar answered Oct 24 '22 01:10

Matt Shipton