Maramal
Maramal

Reputation: 3474

Mongoose document type declaration

I know maybe this is far too basic but I can't recall how to do this properly. I want to declare a Mongoose document to use VS Code IntelliSense for retrieve data.

Right now, document is declared as any since findById() returns any:

const document = await MyModel.findById(docId);

So, whenever I want to call to something like document.updateOne() I don't have intelliSense on.

I have tried using something like:

import { Model, Document } from 'mongoose';
...
const document: Model<Document> = await MyModel.findById(docId);

But this don't give me the ability to refer internal attributes directly like document.title or any other.

So, what is the proper way to declare document?

Upvotes: 3

Views: 4371

Answers (4)

Linda Paiste
Linda Paiste

Reputation: 42288

Your MyModel has some sort of document type that extends the Mongoose Document type and likely adds some properties of its own. That's the generic that you want to use.

Instead of setting the generic (<Document>) when you retrieve the document, you want to set the generic on the MyModel object itself so that the Typescript will infer the correct type for findById and for any other methods. So you want to handle this at the place where you create MyModel.

interface MyDocument extends Document {
    title: string;
}

const MyModel = mongoose.model<MyDocument>(name, schema);

Now the document is inferred to be type MyDocument | null here:

const document = await MyModel.findById(docId);

Upvotes: 3

sayandcode
sayandcode

Reputation: 3214

The method you mentioned updateOne should work out of the box, once you use the findById method, at this point in time (Feb 2023).

const myDoc = await MyModel.findById(docId);
myDoc.updateOne(/* something */);

In case you still have trouble, and need to type the Document elsewhere, I would suggest the HydratedDocument and HydratedDocumentFromSchema generic types.

type Doc1 = HydratedDocument<typeof MyModel>;

type Doc2 = HydratedDocument<typeof MySchema>;
// or
type Doc2 = HydratedDocument<typeof MyModela.schema>;

You can use any of these depending on what symbols you have available to you.

Upvotes: 1

Sir hennihau
Sir hennihau

Reputation: 1814

The new recommended way of typing documents is using HydratedDocument:


import {  HydratedDocument } from "mongoose";

interface Animal {name: string}

const animal: HydratedDocument<Animal> = AnimalModel.findOne( // ...

https://mongoosejs.com/docs/typescript.html

Upvotes: 3

Mr. X
Mr. X

Reputation: 897

This worked for me:

export const findPostById = async (postId: any): Promise<HydratedDocument<typeof Post.schema.obj>> => {
    const post = await Post.findById(postId);
    return (post as HydratedDocument<typeof Post.schema.obj>);
};

Upvotes: 1

Related Questions