xerotolerant
xerotolerant

Reputation: 2089

Mongoose Property 'x' does not exist on type 'Document'

The ts compiler says that none of the properties exist on type 'Document'.

It seems that because of this none of the properties on the model can be set. If I print a user object to the console all I get is {"_id":"long hex id number"}

My model is configured as follows:

users.ts

import * as mongoose from 'mongoose';
import * as crypto from 'crypto';
import * as jwt from 'jsonwebtoken';

var userSchema = new mongoose.Schema({
    email: {
        type: String,
        unique: true,
        required: true
    },
    firstMidname: {
        type: String,
        required: true
    },
    lastName: {
        type: String,
        required: true
    },
    hash: String,
    salt: String
});

userSchema.methods.setPassword = setPassword;


userSchema.methods.validPassword = validPassword;

userSchema.methods.generateJwt = generateJwt;

export = mongoose.model('User', userSchema);

Api connection point api.ts

import * as express from    'express';
import * as mongoose from   'mongoose';
import * as passport from   'passport';

var User = mongoose.model('User');

var router = express.Router();

router.post('/', createUser);

function createUser(req, res){
var user = new User();
    console.log(user);
    user.firstMidName = req.body.firstName;
    user.lastName = req.body.lastName;
    user.setPassword(req.body.password);

    user.save((err) => {
        console.log("saving user");
        var token;
        token = user.generateJwt();
        res.status(200);
        res.json({
            'token': token
        });
    });
}

export = router;

How can I fix or troubleshoot this issue? Nothing in the user.save block executes.

EDIT: The two things seem to be unrelated. I can now save to the database however the typescript error persists. Is this expected behaviour?

Upvotes: 19

Views: 34005

Answers (5)

Singingsongs
Singingsongs

Reputation: 11

As clearly stated by @creme332, the findByIdAndRemove() method is only available in mongoose v7, and entirely removed in mongoose v8.

use findByIdAndDelete() instead. it work just find without extending any class.

Upvotes: 0

creme332
creme332

Reputation: 1935

Problem

I had the Post model defined as follows:

import mongoose from "mongoose";

export interface iPost {
  title: string;
}

const Schema = mongoose.Schema;

const PostSchema = new Schema<iPost>({
  title: {
    type: String,
  }
});

export default mongoose.model("Post", PostSchema);

I tried using Post.findByIdAndRemove(...); but got the following error:

Property 'findByIdAndRemove' does not exist on type 'Model<iPost, {}, {}, {}, Document<unknown, {}, iPost> & iPost & { _id: ObjectId; }, Schema<iPost, Model<iPost, any, any, any, Document<unknown, any, iPost> & iPost & { ...; }, any>, ... 6 more ..., Document<...> & ... 1 more ... & { ...; }>>'.

I tried making my iPost interface extend mongoose.Document as suggested by the other answers but it did not work.

Solution

The findByIdAndRemove() method is only available in mongoose v7 while I was using mongoose v8. The equivalent method for mongoose v8 is findByIdAndDelete().

In Mongoose v8, there is also no need to make your interface extend mongoose.Document.

Conclusion

Use the mongoose documentation for your mongoose version to verify that the mongoose property that you are trying to use actually exists.

Upvotes: 0

Justin Herrera
Justin Herrera

Reputation: 653

Fixed this by adding interface upon declaration of schema

interface UserInterface extends Document {
  email: string;
}

const User = new Schema<UserInterface>({
  email: String;
})

Upvotes: 1

Jim
Jim

Reputation: 4170

When I defined my entity interface I had it extending "Document" but had not imported anything.

When I crtl+click on it though I can see that it incorrectly thinks I was referring to the built-in node object "Document":

/** Any web page loaded in the browser and serves as an entry point into the web page's content, which is the DOM tree. */
interface Document extends Node, DocumentAndElementEventHandlers, DocumentOrShadowRoot, GlobalEventHandlers, NonElementParentNode, ParentNode, XPathEvaluatorBase {

After I explicitly told it to use Document from the mongoose library things worked. 👍

import { Document } from 'mongoose';

Upvotes: 2

Nick Bernard
Nick Bernard

Reputation: 780

The mongoose.model method accepts a type that defaults to mongoose.Document, which won't have properties you want on your User document.

To fix this, create an interface that describes your schema and extends mongoose.Document:

export interface UserDoc extends mongoose.Document {
  email: {
    type: string;
    unique: boolean;
    required: boolean;
  }
  ...
}

Then, pass that through as the type for your model:

export = mongoose.model<UserDoc>('User', userSchema);

Upvotes: 24

Related Questions