Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
26.96k stars 3.84k forks source link

insertMany return type incompatible with InsertManyResult<T> (TypeScript) #13904

Closed andrii-kasparevych closed 1 year ago

andrii-kasparevych commented 1 year ago

Prerequisites

Mongoose version

7.5.3

Node.js version

v18.13

MongoDB server version

7.x

Typescript version (if applicable)

No response

Description

While migrating a NestJs/TypeScript project from mongoose v6.10.3 to v7.5.3, I have faced a problem with the return type of Model.insertMany method. I have a method handling creating many records and then reporting the errors/duplicated/created documents, where I directly use InsertManyResult type from mongoose, and the typed assignment like below is crucial.

const insertManyResult: InsertManyResult<ITest> = await Test.insertMany(
      [{ name: "test" }],
      {
        ordered: false,
        rawResult: true
      }
    );

The compile error boils down to:

...        Type 'Error' is not assignable to type 'CastError | ValidatorError'.
          Type 'MongooseError' is missing the following properties from type 'ValidatorError': properties, kind, path, valuets(2322)

Similar code worked in v6.10.3, but this commit has introduced a new overload for insertMany which is as follows:

    insertMany<DocContents = TRawDocType>(
      doc: DocContents | TRawDocType,
      options: InsertManyOptions & { ordered: false; rawResult: true; }
    ): Promise<mongodb.InsertManyResult<Require_id<DocContents>> & {
      mongoose: {
        validationErrors: Error[];
        results: Array<
          Error |
          Object |
          MergeType<THydratedDocumentType, DocContents>
        >
      }
    }>;

while the exported InsertManyResult type looks like this:

  type InsertManyResult<T> = mongodb.InsertManyResult<T> & {
    insertedIds: {
      [key: number]: InferId<T>;
    };
    mongoose?: { validationErrors?: Array<Error.CastError | Error.ValidatorError> };
  };

And the error is caused by validationErrors: Error[] being incompatible with validationErrors?: Array<Error.CastError | Error.ValidatorError>.

While I could fix the issue by adding a custom type

type InsertManyResultFixed<T> = Omit<InsertManyResult<T>, 'mongoose'> & {
  mongoose: {
    validationErrors: Error[];
  };
};

I would prefer to use the library types.

Steps to Reproduce

import { InsertManyResult, Schema, model } from "mongoose";

const schema = new Schema({ name: String });

interface ITest {
  name?: string;
}
const Test = model<ITest>("Test", schema);

export class InsertManyDemo {
  public async createMany() {

     // the assignment below gives compile error
    const insertManyResult: InsertManyResult<ITest> = await Test.insertMany(
      [{ name: "test" }],
      {
        ordered: false,
        rawResult: true
      }
    );
    return insertManyResult;
  }
}

Link to the sandbox with demo: https://codesandbox.io/s/typescript-playground-forked-9mjzg5?file=/src/index.ts

Expected Behavior

The code compiles and InsertManyResult<T> type actually represents what 'insertMany' returns.

scabezas632 commented 1 year ago

Same problem here, I had to downgrade to 7.5.2 version