使用 Zod 验证将错误添加到具有嵌套模式的上下文中

问题描述 投票:0回答:1

我有一个使用 Zod 验证数据的 Typescript 应用程序。该模式包括多个模式,这些模式的值与其他模式表示的嵌套字段略有不同,因为它们可以在其他地方重用。

有一个嵌套对象,当某个级别以下的任何对象都会向 Zod 上下文添加一个额外的错误。像这样的例子

{
  a: {
    b: { // d or e should both add another error
      d: "1",
      e: "3",
    },
  },
}

因此,如果 d 验证失败,我希望将标准 Zod 验证错误和自定义错误添加到上下文中。阅读它似乎我想使用 superRefine 来做到这一点。但是,如果我添加 superRefine,如果验证失败发生在嵌套模式中,它似乎不会触发。

代码:https://github.com/rlperez/so-demo-zod

如果我有这样的模式:

const BazSchema = z.string();

const BarSchema = z.object({
  baz: BazSchema
});

const FooSchema = z.object({
  bar: BarSchema
});

当我调用

FooSchema.parse(obj)
时,BazSchema 失败不会触发 superRefine,如果它是这样写的:

const FirstSuperRefinedFooSchema = FooSchema.superRefine((data, ctx) => {
  if(!BarSchema.safeParse(data).success) {
    ctx.addIssue({
      code: 'custom',
      message: 'first super refined custom message',
    });
  }
});

并且被称为这样

  let parseResult = FooSchema.safeParse(wrongTypeBaz);

输出

> [email protected] dev
> npx tsc -t 'es2017' && node ./src/main.js

stupid demo

FirstSuperRefinedFoo
mapping invalid_type
{"error":[{"code":"invalid_type","expected":"object","received":"undefined","path":["bar"],"message":"Required"}]}

期望它也会有自定义错误。我添加了打印语句以确保它不会达到 superRefine。就好像它不会比事件发生的地方进一步引发事件。我需要手动将其添加到每个架构中吗?这似乎需要在这个模式中进行大量复制和粘贴才能做到这一点。

如何做到这一点?

javascript typescript zod
1个回答
0
投票

您可以使用superRefine。但是,您需要确保 superRefine 应用于适当的架构级别。我们已经知道嵌套模式验证错误不会传播到父模式 superRefine,因此您必须处理每个相关模式中的自定义错误逻辑。

import { z } from "zod";

// Define the innermost schema with superRefine
const BazSchema = z.string().superRefine((data, ctx) => {
  if (typeof data !== "string") {
    ctx.addIssue({
      code: "custom",
      message: "Baz must be a string",
    });
  }
});

// Define the next schema level with superRefine
const BarSchema = z.object({
  baz: BazSchema
}).superRefine((data, ctx) => {
  if (!BazSchema.safeParse(data.baz).success) {
    ctx.addIssue({
      code: "custom",
      message: "Bar's baz field must be a valid Baz",
    });
  }
});

// Define the outermost schema with superRefine
const FooSchema = z.object({
  bar: BarSchema
}).superRefine((data, ctx) => {
  if (!BarSchema.safeParse(data.bar).success) {
    ctx.addIssue({
      code: "custom",
      message: "Foo's bar field must be a valid Bar",
    });
  }
});

// Example usage
const wrongTypeBaz = {
  bar: {
    baz: 123, // This should fail as BazSchema expects a string
  },
};

const parseResult = FooSchema.safeParse(wrongTypeBaz);

if (!parseResult.success) {
  console.log(parseResult.error.format());
}
© www.soinside.com 2019 - 2024. All rights reserved.