我有一个使用 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。就好像它不会比事件发生的地方进一步引发事件。我需要手动将其添加到每个架构中吗?这似乎需要在这个模式中进行大量复制和粘贴才能做到这一点。
如何做到这一点?
您可以使用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());
}