node.jstypescriptmongodbmongoosetypegoose

Mongoose (Typegoose) extension method type error


Currently when id is provided to findOneAndUpdate, it doesn't return auto generated id.

So I have created extension method to overcome this issue. But typescript is complaining about typings. Need help with that.

I have created extension method as below.

declare module 'mongoose' {
  interface Model<T>
    extends NodeJS.EventEmitter,
      AcceptsDiscriminator {
    findOneAndUpsert<T>(
      filter?: FilterQuery<T>,
      update?: UpdateQuery<T>,
      options?: QueryOptions | null,
      callback?: (err: any, doc: T | null, res: any) => void,
    ): Promise<QueryWithHelpers<T | null, T>>; // Here I am getting error as "Type 'T' does not satisfy the constraint 'Document<any, {}>'"
  }
}



mongoose.model.prototype.findOneAndUpsert = async function <
  T extends mongoose.Document<any, {}>
>(
  filter?: FilterQuery<T>,
  update?: UpdateQuery<T>,
  options?: QueryOptions | null,
  callback?: (err: any, doc: T | null, res: any) => void,
): Promise<QueryWithHelpers<T | null, T>> {
  const model = this as mongoose.Model<T>;
  if (filter.id) {
    return model.findOneAndUpdate(filter, update);
  } else {
    return model.findById((await model.create((update as any).$set)).id);
  }
};

I want to use it like below.

datasource = await DatasourceModel(
      await this.projectContext,
    ).findOneAndUpsert(
      { id: datasource.id },
      {
        $set: {
          name: datasource.name,
          type: datasource.type,
          source: datasource.source,
        },
      },
    );

My datasource model looks like below.

export class Datasource extends ModelBase {
  @prop()
  authTokenId?: number;
}

export const DatasourceModel = (connection: Connection) => {
  return getModelForClass(Datasource, connection);
};

during declaration I am getting error as "Type 'T' does not satisfy the constraint 'Document<any, {}>'"?

If I write "T extends mongoose.Document<any, {}>" in model declaration, then not giving error, but then during calling the method it gives error as "Property 'name' is missing in type 'Document<any, {}>' but required in type 'Datasource'"

Can anyone help with that what I need to do here?


Solution

  • ok following signature worked for me. I was adding extends to both signature and actual implementation. But in model signature extend is not required as by default it goes to extended only.

    declare module 'mongoose' {
      interface Model<T>
        extends NodeJS.EventEmitter,
          AcceptsDiscriminator {
        findOneAndUpsert<T>( 
          filter?: FilterQuery<T>,
          update?: UpdateQuery<T>,
          options?: QueryOptions | null,
          callback?: (err: any, doc: T | null, res: any) => void,
        ): Promise<T>;
      }
    }