Typescript – 将Zod模式的结果作为参数传递给函数的泛型约束

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

Typescript - Generic constraint to pass zod schema result into function as argument

问题

以下是您要翻译的内容:

"I am trying to build a custom controller function to reduce the bloat of my application. Wrapping try-catch, parsing a zod schema, and then merging the request zod schema into a single object exists in all of the handler functions, hence I wanted to have a wrapper to handle these for each request. But I want to ensure type safety while doing so. Here is the function I have so far:

function controller<
  T extends B & Q & P,
  B extends Record<string, any>,
  Q extends Record<string, any>,
  P extends Record<string, any>
>(handlerFn: (args: T) => Promise<any>, zodSchema: { parse: (data: unknown) => { body: B; query: Q; params: P } }) {
  return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
    try {
      const r = zodSchema.parse(req);
      const args = { ...r.body, ...r.params, ...r.query };
      await handlerFn(args);
    } catch (e) {
      next(e);
    }
  };
}

It takes a handlerFn, which is the core function, which takes a parameter T. It takes a zodSchema as its second parameter, in which after parsing should validate and return body, query, and params fields since we are going to validate the Request object. I want the input of the handlerFn to be merged body, query, and params.

Here is the error I am getting:

Argument of type 'B & P & Q' is not assignable to parameter of type 'T'.
  'B & P & Q' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Record<string, any>'.

Any help is appreciated."

英文:

I am trying to build a custom controller function to reduce the bloat of my application. Wrapping try-catch, parsing a zod schema, and then merging the request zod schema into single object exists in all of the handler functions, hence I wanted to have a wrapper to handle these for each request. But I want to ensure type safety while doing so. Here is the function I have so far:

function controller&lt;
  T extends B &amp; Q &amp; P,
  B extends Record&lt;string, any&gt;,
  Q extends Record&lt;string, any&gt;,
  P extends Record&lt;string, any&gt;
&gt;(handlerFn: (args: T) =&gt; Promise&lt;any&gt;, zodSchema: { parse: (data: unknown) =&gt; { body: B; query: Q; params: P } }) {
  return async (req: express.Request, res: express.Response, next: express.NextFunction) =&gt; {
    try {
      const r = zodSchema.parse(req);
      const args = { ...r.body, ...r.params, ...r.query };
      await handlerFn(args);
    } catch (e) {
      next(e);
    }
  };
}

It takes a handlerFn, which is the core function, which takes a parameter T. It takes a zodSchema as its second parameter, in which after parsing should validate and return body, query, and params fields since we are going to validate the Request object. I want the input of the handlerFn to be merged body, query, and params.

Here is the error I am getting:

Argument of type &#39;B &amp; P &amp; Q&#39; is not assignable to parameter of type &#39;T&#39;.
  &#39;B &amp; P &amp; Q&#39; is assignable to the constraint of type &#39;T&#39;, but &#39;T&#39; could be instantiated with a different subtype of constraint &#39;Record&lt;string, any&gt;&#39;.

Any help is appreciated.

答案1

得分: 1

The problem is that T extends B & Q & P is not the same as T = B & Q & P, and T may have some other fields; thus, B & Q & P won't be considered as T. Instead of using T just use B & Q & P directly on the handlerFn:

function controller<
  B extends Record<string, any>,
  Q extends Record<string, any>,
  P extends Record<string, any>
>(
  handlerFn: (args: B & Q & P) => Promise<any>,
  zodSchema: { parse: (data: unknown) => { body: B; query: Q; params: P } }
) {
  return async (req: any, res: any, next: any) => {
    try {
      const r = zodSchema.parse(req);
      const args = { ...r.body, ...r.params, ...r.query };
      await handlerFn(args);
    } catch (e) {
      next(e);
    }
  };
}
英文:

The problem is that T extends B &amp; Q &amp; P is not the same as T = B &amp; Q &amp; P, and T may have some other fields; thus, B &amp; Q &amp; P won't be considered as T. Instead of using T just use B &amp; Q &amp; P directly on the handlerFn:

function controller&lt;
  B extends Record&lt;string, any&gt;,
  Q extends Record&lt;string, any&gt;,
  P extends Record&lt;string, any&gt;
&gt;(
  handlerFn: (args: B &amp; Q &amp; P) =&gt; Promise&lt;any&gt;,
  zodSchema: { parse: (data: unknown) =&gt; { body: B; query: Q; params: P } }
) {
  return async (req: any, res: any, next: any) =&gt; {
    try {
      const r = zodSchema.parse(req);
      const args = { ...r.body, ...r.params, ...r.query };
      await handlerFn(args);
    } catch (e) {
      next(e);
    }
  };
}

huangapple
  • 本文由 发表于 2023年5月25日 23:30:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76333985.html
匿名

发表评论

匿名网友

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

确定