You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在React Hook Form中使用Zod时refine()/superrefine()失效求助

解决Zod superRefine自定义提示不生效的问题

你的问题核心在于Zod的校验执行顺序:基础类型校验会优先于superRefine逻辑执行。当fieldCodeToConcat传入数组时,你定义的z.object().optional()会先触发类型校验错误,直接返回默认的"Expected object, received array",根本不会进入superRefine的自定义校验逻辑,所以自定义提示永远无法触发。

解决方案:放宽基础类型校验,将逻辑移至superRefine

通过z.union放宽fieldCodeToConcat的基础类型限制,允许数组、对象或undefined通过,再在superRefine中集中处理所有校验规则,确保自定义提示能正常触发:

const defineFieldLineSchema = z.object({
  accountingFieldCode: z.object({
    fieldCode: z.string(),
    fieldCodeName: z.string(),
    description: z.string().nullable(),
  }),
  accountingOutputName: z.string().min(1, "Field is required"),
  defaultValueApplicable: z.string(),
  defaultValue: z.string().optional(),
  prefixValue: z.string().optional(),
  suffixValue: z.string().optional(),
  fieldCodeConcatRequired: z.enum(["Y", "N"]),
  concatCharacter: z.string(),
  // 放宽基础类型:允许object、数组、undefined通过
  fieldCodeToConcat: z.union([
    z.object({
      fieldCode: z.string(),
      fieldCodeName: z.string(),
      description: z.string().nullable(),
    }),
    z.array(z.any()),
    z.undefined()
  ]),
  maxDataLength: z.number(),
}).superRefine((data, ctx) => {
  // 校验1:当fieldCodeConcatRequired为Y时,必须提供fieldCodeToConcat
  if (data.fieldCodeConcatRequired === "Y" && !data.fieldCodeToConcat) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: "fieldCodeToConcat is required when fieldCodeConcatRequired is 'Y'",
      path: ["fieldCodeToConcat"],
    });
  }
  // 校验2:fieldCodeToConcat不能是数组
  if (Array.isArray(data.fieldCodeToConcat)) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: "fieldCodeToConcat must be an object, not an array",
      path: ["fieldCodeToConcat"],
    });
  }
  // 可选:额外校验fieldCodeToConcat的结构(当它是对象时)
  if (data.fieldCodeToConcat && !Array.isArray(data.fieldCodeToConcat)) {
    const objSchema = z.object({
      fieldCode: z.string(),
      fieldCodeName: z.string(),
      description: z.string().nullable(),
    });
    const parseResult = objSchema.safeParse(data.fieldCodeToConcat);
    if (!parseResult.success) {
      parseResult.error.issues.forEach(issue => {
        ctx.addIssue({
          ...issue,
          path: ["fieldCodeToConcat", ...issue.path]
        });
      });
    }
  }
})

备选方案:用preprocess拦截值

如果不想放宽基础类型,可以用z.preprocess拦截传入值,避免基础校验提前报错:

const defineFieldLineSchema = z.object({
  // 其他字段保持不变
  fieldCodeToConcat: z.preprocess((val) => {
    // 保留数组值,让superRefine处理校验
    if (Array.isArray(val)) return val;
    return val;
  }, z.object({
    fieldCode: z.string(),
    fieldCodeName: z.string(),
    description: z.string().nullable(),
  }).optional()),
  // 其他字段保持不变
}).superRefine((data, ctx) => {
  // 执行相同的自定义校验逻辑
  if (data.fieldCodeConcatRequired === "Y" && !data.fieldCodeToConcat) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: "fieldCodeToConcat is required when fieldCodeConcatRequired is 'Y'",
      path: ["fieldCodeToConcat"],
    });
  }
  if (Array.isArray(data.fieldCodeToConcat)) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      message: "fieldCodeToConcat must be an object, not an array",
      path: ["fieldCodeToConcat"],
    });
  }
})

额外注意事项

确保在React Hook Form中正确配置Zod解析器:

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

const form = useForm({
  resolver: zodResolver(defineFieldLineSchema),
  // 其他配置
});

内容的提问来源于stack exchange,提问作者Shiladitya Thakur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 16:25:13