4
votes

Typescript is complaining at this line:

user.posts.pull(postId);

I am getting this error:

     Property 'pull' does not exist on type 'PostDoc[]'

since postId is received as req.params.postId it is type string, so i converted it to mongoose objectId but i still have the same error:

  user.posts.pull(mongoose.Types.ObjectId(postId));

pull() works in mongoose arrays. this line of code how I implemented in javacsript. I am converting my project to typescript. this is the user interface and schema for user model.

interface UserDoc extends mongoose.Document {
  email: string;
  password: string;
  posts: PostDoc[];
  name: string;
  status: string;
}
const userSchema = new Schema({
  email: { type: String, required: true },
  password: { type: String, required: true },
  name: { type: String, required: true },
  status: { type: String, default: "I am a new user" },
  posts: [{ type: Schema.Types.ObjectId, ref: "Post" }],
});

Here post schema and interface

interface PostDoc extends Document {
  title: string;
  content: string;
  imageUrl: string;
  creator: Types.ObjectId;
}
const postSchema = new Schema(
  {
    title: {
      type: String,
      required: true,
    },
    imageUrl: {
      type: String,
      required: true,
    },
    content: {
      type: String,
      required: true,
    },
    creator: {
      type: Schema.Types.ObjectId,
     ref: "User",
      required: true,
    },
  },
  { timestamps: true }
1
If you see the error message, Property 'pull' does not exist on type 'PostDoc[]', it tells you everything you need to knowKunal Mukherjee
@KunalMukherjee same line of code works in javascript. just switching to typescript, does not mean that, they discarded pull method?Yilmaz
Please add your post schema in the question, does it extend mongoose.Document ?Kunal Mukherjee
Also try adding the npm package as a dev dependency - npmjs.com/package/@types/mongooseKunal Mukherjee
In the interface PostDoc the Document refers to mongoose.Document right, have you destructured it on the top ?Kunal Mukherjee

1 Answers

4
votes

I faced a similar problem to properly type the subdocuments. I propose you the following solution in order to keep both the DTO interface and the model interface separated and strongly typed. The same would apply for your PostDoc.

UserDoc DTO

interface UserDoc {
  email: string;
  password: string;
  posts: PostDoc[];
  name: string;
  status: string;
}

UserDoc Model

export type UserDocModel = UserDoc & mongoose.Document & PostDocModel & Omit<UserDoc , 'posts'>

interface PostDocModel {
  posts: mongoose.Types.Array<PostModel>;
};

We replace the posts: PostDoc[] property with Omit for our mongoose array of PostModel, maintaining the properties synchronized. Inspiration from https://stackoverflow.com/a/36661990

In this way we could access every mongoose array method such as pull, pop, shift, etc. (https://mongoosejs.com/docs/api.html#Array)

const user = await this.userdocModel.findById(userId).exec();
user.posts.pull(postId);

Exporting the model

const User = mongoose.model<UserDocModel>('User', userSchema);
export default User;