Mongoose Model Types Issue: Extending Class Breaks populate Method

42 views Asked by At

I'm working on a substantial project with three codebases: data access layer (DAL) as the backend, and two APIs for admin and client. The DAL codebase defines all schemas and mongoose models and exports them for use by other codebases as dependencies.

Here's a simplified structure of the DAL model:

interface ExampleInterface {}

const exampleSchema: mongoose.Schema<ExampleInterface> = new mongoose.Schema<ExampleInterface>({});

const ExampleModel = mongoose.model<ExampleInterface>("Example", exampleSchema);

class Example extends ExampleModel {}

The Example class is then exported as BaseExample for use in other packages.

In another package where the DAL is utilized:

class Example extends BaseExample {
  doSomething = async (): Promise<string> => {
    return "Doing something...";
  };
}

Previously, I could populate fields like this:

await Example.populate(this, [
  {
    path: "x",
    model: XClass, // not the model
  },
  {
    path: "y",
    model: YClass, // not the model
  },
]);

It's important to note that before, mongoose was not added as a dependency (mistakenly), and I had no issues running the project on my Mac. However, a coworker who was on Windows encountered errors indicating that mongoose wasn't added as a dependency.

After my coworker installed mongoose as a dependency and ran npx tsc, the type definitions changed from

import mongoose from "mongoose";
import BannerDBI from "./index.model.interfaces";
export declare const BannerModel: mongoose.Model<BannerDBI, {}, {}>;
declare class Banner extends BannerModel {
}
export default Banner;

export default BackgroundSoundSetting;

to this:

import mongoose from "mongoose";
import BannerDBI from "./index.model.interfaces";
import { Types } from "mongoose";
export declare const BannerModel: mongoose.Model<BannerDBI, {}, {}, {}, mongoose.Document<unknown, {}, BannerDBI> & import("./index.model.interfaces").BannerI & mongoose.Document<any, any, import("./index.model.interfaces").BannerI> & {
    _id: Types.ObjectId;
    createdAt: Date;
    updatedAt: Date;
} & {
    _id: Types.ObjectId;
}, any>;
declare class Banner extends BannerModel {
}
export default Banner;

and I can no longer pass the Example class to the populate method as a model. Casting the class to Model also didn't help.

Using // @ts-ignore didn't work either; it only returned plain JSON, preventing me from using the class's methods.

I could create an instance of the class from the returned JSON, but it's less clean. Moreover, adding instances to the model following mongoose's recommended way only fixes the problem in the DAL package, not in the API packages, where I extend the Example class further for custom functionality.

Is there a way to fix this issue or a better approach to handle it? Any help would be greatly appreciated.

I've tried:

Casting the class to Model - didn't work. Using // @ts-ignore - still returned plain JSON and not an instance of the given class.

I was expecting to continue using the Example class as a model for the populate method and expecting the returned object to be an instance of the given class and not simply a plain js object.

0

There are 0 answers