'Using Mongoose and Typescript, what type should be used for a ref field of an interface?

I am using mongoose and Typescript, and I am wanting to know what type, or types, I should be using for a reference field, when creating an interface? Consider the following two related interfaces:

interface ICat {
  name: string,
  colour: string,
}

interface ICatDB extends ICat, Document {};

interface IMouse {
  name: string,
  colour: string,
  chasedBy: /* ... */
}

interface IMouseDB extends IMouse, Document {};

And the schemas and models that use them:

let cat = new Schema({
  name: String,
  colour: String,
});

mongoose.model<ICatDB>('Cat', cat);
let mouse = new Schema({
  name: String,
  colour: String,
  chasedBy: { type: Schema.Types.ObjectId, ref: 'Cat' }
});

mongoose.model<IMouseDB>('Mouse', mouse);

For the chasedBy field we need to consider that it can take values in three forms:

  • String or ObjectId, when passed to a create() method
  • ObjectId when returned from Mongoose
  • Instance of ICat when returned from Mongoose, using populate()

Is there a way that we can specify the types the interface can support, without having to resort to using any?

BTW we separated IMouse and IMouseDB, since Typescript wanted all the fields for Document filled out every time we created a new IMouse object, so this was a work around.



Solution 1:[1]

At least for version 5.x you could use this: https://mongoosejs.com/docs/5.x/docs/typescript/populate.html

import { PopulatedDoc } from 'mongoose';
import ICat from './ICat';

interface IMouse {
  name: string,
  colour: string,
  chasedBy: PopulatedDoc<ICat>
}

The docs in 6.x shows different approach:
https://mongoosejs.com/docs/typescript/populate.html
like this:

MouseModel.findOne({}).populate<{chasedBy: ICat}>('chasedBy');

Solution 2:[2]

Lacking any alternative answer, I went with:

import { ObjectID } from 'mongodb';
import ICat from './ICat';

interface IMouse {
  name: string,
  colour: string,
  chasedBy: string | ObjectID | ICat
}

This describes the type variants for the 'chasedBy' property. As to whether this is the recommended approach, I can't say.

Solution 3:[3]

Mongoose 6.x

Mongoose offers type declarations in mongoose.Types

interface Mouse { // important: don't use I in front of the name and don't extend Document
  chasedBy: mongoose.Types.ObjectId
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Andre M
Solution 3 winklerrr