How can I use MongooseArray.prototype.pull() with typescript?

Viewed 876

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 Answers

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;
Related