How to Type the '_id' Field in TypeScript with Mongoose
Hi everyone, let me start by thanking you for reading this post. I started this to practice my writing skills in English and to overcome my procrastination. Writing posts like this helps me gain a better understanding of things I'm learning. Let's dive into it. I encountered an issue while writing code in typescript using the popular Mongoose library when I tried to convert the field _id to a string. I have some example code here: @Schema({ timestamps: true, collection: 'products' }) export class ProductModel { _id: mongoose.Schema.Types.ObjectId; @Prop({ required: true }) name: string; @Prop() description: string; @Prop({ required: true }) price: number; @Prop({ required: true, default: 0 }) stock: number; } const product = new ProductModel(); // example of instance product._id.toString(); // trying to convert my _id to a string I'm using Nestjs and its Mongoose integration. Instead of writing plain schemas like we traditionally do, this library allow us to define models and their properties using Decorators (@prop) in a class, all within the same file. This class also serves as our model. There are 2 lines I want us to focus on: const product = new ProductModel(); product._id.toString(); Specifically to the second line where we call .toString(). It turns out that the way we declared the _id property in our class causes incorrect typing. The library defines two types for ObjectId: the first is implemented under mongoose.Schema.Types.ObjectId , and the other is mongoose.Types.ObjectId. The difference between these types is that they aren't interchangeable, the latter is the declaration of an object which has serializable methods like toString(), while the former doesn't. So I'll show you the error from the typescript linter if you use the former. Instead of writing something like this to silence the linter: (product._id as ObjectId).toString() Try using the correct type for your class, which is mongoose.Types.ObjectId @Schema({ timestamps: true, collection: 'products' }) export class ProductModel { _id: mongoose.Types.ObjectId; } It doesn't matter if you are not using NestJS and Decorators. The type you need to import is the same. The example below use an interface and plain Mongoose. interface Product { _id: mongoose.Types.ObjectId; } const myProductModel = mongoose.Schema({ ... // props }) Bye Well, that's a short post, just in case someone else needs this, and for me because after one week without using Mongoose, I forget it XD. I think it would be interesting to investigate more about these 2 types and why they are written in that way, under different objects. In summary, we need to make sure we're typing our properties with the correct type before trying to bypass the Typescript compiler using type coercion or some other trick. Thank you for reading ❤️

Hi everyone, let me start by thanking you for reading this post.
I started this to practice my writing skills in English and to overcome my procrastination. Writing posts like this helps me gain a better understanding of things I'm learning. Let's dive into it.
I encountered an issue while writing code in typescript using the popular Mongoose library when I tried to convert the field _id to a string.
I have some example code here:
@Schema({ timestamps: true, collection: 'products' })
export class ProductModel {
_id: mongoose.Schema.Types.ObjectId;
@Prop({ required: true })
name: string;
@Prop()
description: string;
@Prop({ required: true })
price: number;
@Prop({ required: true, default: 0 })
stock: number;
}
const product = new ProductModel(); // example of instance
product._id.toString(); // trying to convert my _id to a string
I'm using Nestjs and its Mongoose integration. Instead of writing plain schemas like we traditionally do, this library allow us to define models and their properties using Decorators (@prop) in a class, all within the same file. This class also serves as our model.
There are 2 lines I want us to focus on:
const product = new ProductModel();
product._id.toString();
Specifically to the second line where we call .toString()
. It turns out that the way we declared the _id
property in our class causes incorrect typing.
The library defines two types for ObjectId
: the first is implemented under mongoose.Schema.Types.ObjectId
, and the other is mongoose.Types.ObjectId
.
The difference between these types is that they aren't interchangeable, the latter is the declaration of an object which has serializable methods like toString()
, while the former doesn't.
So I'll show you the error from the typescript linter if you use the former.
Instead of writing something like this to silence the linter: (product._id as ObjectId).toString()
Try using the correct type for your class, which is mongoose.Types.ObjectId
@Schema({ timestamps: true, collection: 'products' })
export class ProductModel {
_id: mongoose.Types.ObjectId;
}
It doesn't matter if you are not using NestJS and Decorators. The type you need to import is the same. The example below use an interface and plain Mongoose.
interface Product {
_id: mongoose.Types.ObjectId;
}
const myProductModel = mongoose.Schema<Product>({ ... // props })
Bye
Well, that's a short post, just in case someone else needs this, and for me because after one week without using Mongoose, I forget it XD. I think it would be interesting to investigate more about these 2 types and why they are written in that way, under different objects.
In summary, we need to make sure we're typing our properties with the correct type before trying to bypass the Typescript compiler using type coercion or some other trick.
Thank you for reading ❤️