node.js - Cum adaug metode statice unui model Mongoose în Typescript pentru Mongoose 5.11?


În Mongoose 5.10, am folosit următorul model pentru a adăuga metode statice la modelele mele Mongoose:

import { Schema, Document, Model, Connection } from "mongoose";
import { v4 } from "uuid";

export interface IFoo extends Document {
  id: string;
  name: string;
}

export interface IFooModel extends Model<IFoo> {
  findOneOrCreate({ name }: { name: string }): Promise<IFoo>;
}

const fooSchema = new Schema({
  id: {
    type: String,
    required: true,
    default: () => `a-${v4()}`,
  },
  name: {
    type: String,
    required: true,
    unique: true,
  },
});

fooSchema.static({
  findOneOrCreate: async function (
    this: IFooModel,
    { name }: { name: string }
  ): Promise<IFoo> {
    let foo = await this.findOne({ name });
    if (!foo) {
      foo = await this.create({ name });
    }
    return foo;
  },
});

export default function (db: Connection): IFooModel {
  return db.model<IFoo, IFooModel>("Foo", fooSchema);
}

În Mongoose 5.11, Mongoose include propriile definiții de tip Typescript; suprascriind ceea ce era definit în @types/mongoose. Aceste actualizări elimină al doilea parametru de tip din mongoose.model() și duc la următoarele erori de tip:

src/models/foo.ts:40:3 - error TS2741: Property 'findOneOrCreate' is missing in type 'Model<IFoo>' but required in type 'IFooModel'.

40   return db.model<IFoo, IFooModel>("Foo", fooSchema);
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  src/models/foo.ts:10:3
    10   findOneOrCreate({ name }: { name: string }): Promise<IFoo>;
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'findOneOrCreate' is declared here.

src/models/foo.ts:40:19 - error TS2558: Expected 1 type arguments, but got 2.

40   return db.model<IFoo, IFooModel>("Foo", fooSchema);
                     ~~~~~~~~~~~~~~~


Found 2 errors.

Cu noile definiții de tip Mongoose 5.11, care este modalitatea corectă de a adăuga aceste metode statice modelului meu?

Răspuns #1

Cheia este să setezi tipurile generice în constructorul Schema astfel:

const fooSchema = new Schema<IFoo, IFooModel>({
  id: {
    type: String,
    required: true,
    default: () => `a-${v4()}`,
  },
  name: {
    type: String,
    required: true,
    unique: true,
  },
});

Am avut, de asemenea, câteva probleme cu tipul documentului care nu reprezenta tipul modelului returnat, așa că aș sugera să creezi un nou tip union astfel și apoi să folosești tipurile de care ai nevoie în mod corespunzător:

export interface IFoo {
  id: string;
  name: string;
}

type IFooDocument = IFoo & Document;