根据字段值更改 zod 架构对象的一部分?

Change part of zod schema object based on field value?

提问人:Емил Цоков 提问时间:10/26/2023 更新时间:10/27/2023 访问量:113

问:

我有一个带有一些字段的表单和一个开关,用于显示/隐藏表单的某些部分,如下所示:

    <Field name="field1" value={value1} />
    <Field name="field2" value={value2} />
    <Switch value={showShippingAddress} / > 
     { showShippingAddress && (
     <>
     <Field name="field3" value={value3} />
     <Field name="field4" value={value4} />
     </>
    )}

在 zod 模式中,我想实现这样的事情

    z
     .object({
       field1: z.string()
       field2: z.string(),
       showShippingAddress: z.boolean(),
       field3: showShippingAddressValue ? z.required : z.string(), // wrong just for describing desired result
       field4: showShippingAddressValue ? z.string.required.regex('') : z.string(), // also wrong 

问题是我怎样才能以更好的方式做到这一点,比我目前能看到的唯一方式更好:


    z
     .object({
      field1: z.string()
      field2: z.string(),
    })
    .and(
      z.object({
        showShippingAddress: z.boolean(),
        field3: z.string().nullable(),
        field4: z.string().nullable(),
      })
      .superRefine(
        ({ showShippingAddress, field3, field4}, { addIssue }) => {
          if(showShippingAddress && notEmptyCheckHelper(field3)) {
            .addIssue({
              code: z.ZodIssueCode.custom,
              message: `Field3 is required.`
            })
         }

         if(showShippingAddress && notEmptyCheckHelper(field4)) {
           .addIssue({
              code: z.ZodIssueCode.custom,
              message: `Field4 is required.`
           })
         }

         if(showShippingAddress && regexCheckHelper(field4)) {
           .addIssue({
              code: z.ZodIssueCode.custom,
              message: `Field4 is not valid.`
           })
        }

        // if there are more validations on Field 4 the checks here also grow and 
        // the same for more fields  that depend on this showShippingAddress value

    }))

JavaScript ReactJS 打字稿 验证ZOD

评论


答:

1赞 Sarath S Menon 10/27/2023 #1

受歧视的工会正是您正在寻找的。

您将需要 2 个对象,一个将 showShippingAddress 作为文本“true”,另一个将 showShippingAddress 作为文本“false”。然后进行歧视性结合。

所以在你的情况下,这样的事情应该有效

z.discriminatedUnion("showShippingAddressValue", [
    z.object({
        showShippingAddressValue: z.literal(false),
        field1: z.string(),
        field2: z.string(),
        field3: z.string().optional(),
        field4: z.string().optional()
    }),
    z.object({
        showShippingAddressValue: z.literal(true),
        field1: z.string(),
        field2: z.string(),
        field3: z.string(),
        field4: z.string()
    })
]);

请注意,仅使用即可使其成为必填字段,而添加 .optional() 将使该字段成为可选字段。z.string()

所以我上面提供的架构将成功解析:

final.parse({
    showShippingAddressValue: false,
    field1: "some value",
    field2: "some value"
});

final.parse({
    showShippingAddressValue: true,
    field1: "some value",
    field2: "some value",
    field3: "some value",
    field4: "some value"
});

但它将无法解析

final.parse({
    showShippingAddressValue: true,
    field1: "some value",
    field2: "some value"
});

另外,还有一个额外的注意事项,如果您不希望字符串为空,则可能需要使用 .nonempty() 方法

评论

0赞 Емил Цоков 10/30/2023
zod.dev/?id=nonempty 是数组方法,而不是字符串方法
0赞 Sarath S Menon 10/30/2023
但它也适用于字符串,其他数组方法如 min、max 也适用于字符串