如何在TypeScript中为多个方法注册相同的mongoose hook?

huangapple go评论75阅读模式
英文:

How to register same mongoose hook for multiple methods in TypeScript?

问题

以下是已翻译的内容:

根据 https://stackoverflow.com/questions/67268004/how-to-register-same-mongoose-hook-for-multiple-methods 中的答案:

const hooks = [ 'find', 'findOne', 'update' ];

UserSchema.pre( hooks, function( next ) {
    // stuff
}

上述代码在不使用 TypeScript 严格模式时正常工作。一旦启用严格模式,它会报错:No overload matches this call.

我该如何调整代码以解决这个问题?我似乎找不到关于它的详细文档,大多数文档只提供了如何为单个方法而不是一次多个方法做的示例。

英文:

Based on the answer in https://stackoverflow.com/questions/67268004/how-to-register-same-mongoose-hook-for-multiple-methods

const hooks = [ 'find', 'findOne', 'update' ];

UserSchema.pre( hooks, function( next ) {
    // stuff
}

The code above works fine when not using TypeScript in strict mode. As soon as I enable strict mode, it complains: No overload matches this call.

How can I adjust the code to fix this? I can't seem to find much documentation about it, most documentation just offers examples of how to do it for a single method instead of multiple at a time.

答案1

得分: 1

你的hooks变量的推断类型是string[]Schema.pre各种重载

/** Defines a pre hook for the model. */
pre<T = THydratedDocumentType>(
  method: DocumentOrQueryMiddleware | DocumentOrQueryMiddleware[],
  options: SchemaPreOptions & { document: true; query: false; },
  fn: PreMiddlewareFunction<T>
): this;
pre<T = Query<any, any>>(
  method: DocumentOrQueryMiddleware | DocumentOrQueryMiddleware[],
  options: SchemaPreOptions & { document: false; query: true; },
  fn: PreMiddlewareFunction<T>
): this;
pre<T = THydratedDocumentType>(method: 'save', fn: PreSaveMiddlewareFunction<T>): this;
pre<T = THydratedDocumentType>(method: 'save', options: SchemaPreOptions, fn: PreSaveMiddlewareFunction<T>): this;
pre<T = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T = THydratedDocumentType>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T = THydratedDocumentType>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T = M>(method: 'insertMany' | RegExp, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;
pre<T = M>(method: 'insertMany' | RegExp, options: SchemaPreOptions, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;

正如错误消息告诉你的那样,none of these accepts string[] as the method argument,因为有很多有效的字符串值是not valid method names。

然而,如果你更明确地表达你的意图,例如使用query middleware type

type MongooseQueryMiddleware = 'count' | 'estimatedDocumentCount' | 'countDocuments' | 'deleteMany' | 'deleteOne' | 'distinct' | 'find' | 'findOne' | 'findOneAndDelete' | 'findOneAndRemove' | 'findOneAndReplace' | 'findOneAndUpdate' | 'remove' | 'replaceOne' | 'update' | 'updateOne' | 'updateMany';

你可以满足编译器(并让它检查任何拼写错误,例如它可以告诉你如果 findone 被错误地用于 findOne):

import { type MongooseQueryMiddleware } from "mongoose";

// ...

const hooks: MongooseQueryMiddleware[] = ["find", "findOne", "update"];

UserSchema.pre(hooks, function (next) {
    // stuff
});

或者,你也可以内联数组:

UserSchema.pre(["find", "findOne", "update"], function (next) {
    // stuff
});

请注意,如你在上面的评论中所建议的那样使用类型断言 not 是正确的方法。当你这样做时,而不是让编译器检查值是否正确,你坚持要它们正确,所以它不能为你捕获拼写错误:

const hooks = ["find", "findone", "update"] as MongooseQueryMiddleware[];
                    // ^^^^^^^^^

UserSchema.pre(hooks, function (next) {
    // stuff
});
英文:

The inferred type of your hooks variable is string[]. Schema.pre has various overloads:

    /** Defines a pre hook for the model. */
    pre<T = THydratedDocumentType>(
      method: DocumentOrQueryMiddleware | DocumentOrQueryMiddleware[],
      options: SchemaPreOptions & { document: true; query: false; },
      fn: PreMiddlewareFunction<T>
    ): this;
    pre<T = Query<any, any>>(
      method: DocumentOrQueryMiddleware | DocumentOrQueryMiddleware[],
      options: SchemaPreOptions & { document: false; query: true; },
      fn: PreMiddlewareFunction<T>
    ): this;
    pre<T = THydratedDocumentType>(method: 'save', fn: PreSaveMiddlewareFunction<T>): this;
    pre<T = THydratedDocumentType>(method: 'save', options: SchemaPreOptions, fn: PreSaveMiddlewareFunction<T>): this;
    pre<T = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
    pre<T = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
    pre<T = THydratedDocumentType>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
    pre<T = THydratedDocumentType>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
    pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: PreMiddlewareFunction<T>): this;
    pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
    pre<T = M>(method: 'insertMany' | RegExp, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;
    pre<T = M>(method: 'insertMany' | RegExp, options: SchemaPreOptions, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;

As the error message tells you, none of these accepts string[] as the method argument, because there are plenty of valid string values that are not valid method names.

However if you are more specific about your intentions, e.g. using the query middleware type:

  type MongooseQueryMiddleware = 'count' | 'estimatedDocumentCount' | 'countDocuments' | 'deleteMany' | 'deleteOne' | 'distinct' | 'find' | 'findOne' | 'findOneAndDelete' | 'findOneAndRemove' | 'findOneAndReplace' | 'findOneAndUpdate' | 'remove' | 'replaceOne' | 'update' | 'updateOne' | 'updateMany';

you can satisfy the compiler (and get the values checked for any typos, e.g. it could tell you if findone was accidentally used instead of findOne):

import { type MongooseQueryMiddleware } from "mongoose";

// ...

const hooks: MongooseQueryMiddleware[] = ["find", "findOne", "update"];

UserSchema.pre(hooks, function (next) {
    // stuff
});

Alternatively, you could just inline the array:

UserSchema.pre(["find", "findOne", "update"], function (next) {
    // stuff
});

Note that using a type assertion, as suggested in your comment above, is not the right way to go about this. When you do that, rather than letting the compiler check the values you insist to it that they're right, so it can't catch typos for you:

const hooks = ["find", "findone", "update"] as MongooseQueryMiddleware[];
                    // ^^^^^^^^^

UserSchema.pre(hooks, function (next) {
    // stuff
});

huangapple
  • 本文由 发表于 2023年4月17日 17:33:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76033671.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定