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
orObjectId
, when passed to acreate()
methodObjectId
when returned from Mongoose- Instance of
ICat
when returned from Mongoose, usingpopulate()
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.
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
orObjectId
, when passed to acreate()
methodObjectId
when returned from Mongoose- Instance of
ICat
when returned from Mongoose, usingpopulate()
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.
- mongoose v7 improved the docs about TS types of populated documents. – Lin Du Commented May 25, 2023 at 9:15
3 Answers
Reset to default 9At 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');
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.
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
}