
当使用 zod 验证包含对象数组的结构时,`flatten()` 默认无法展开嵌套字段错误;需改用 `error.format()` 方法递归提取每一层(如 `sizes[0].price`)的精确校验失败信息。
在 Zod 中,.flatten() 方法仅对顶层字段(如 sizes)做扁平化处理,不会深入数组元素内部的对象结构。因此,当你传入 sizes: [{}] 时,Zod 能识别出数组非空但首项对象缺失必填字段,却无法将 price、off_price、sell_quantity 的错误映射到对应路径下——最终只返回 "sizes":["Required","Required","Required"] 这类模糊提示,丢失关键定位信息。
要获得真正可操作的嵌套错误结构,应使用 Zod 内置的 .format() 方法。它会按数据路径(如 ['sizes', 0, 'price'])生成嵌套对象格式的错误树,完美保留层级语义:
import { z } from 'zod';
const schema = z.object({
sizes: z
.array(
z.object({
price: z.string().nonempty("价格不能为空"),
off_price: z.string().nonempty("折扣价不能为空"),
sell_quantity: z.string().nonempty("销量不能为空"),
})
)
.nonempty("至少需提供一个规格"),
}).strict();
const result = schema.safeParse({ sizes: [{}] });
if (!result.success) {
// ✅ 推荐:获取结构化嵌套错误
const formatted = result.error.format();
console.log(formatted.sizes?.[0]);
// 输出:
// {
// _errors: [],
// price: { _errors: ["价格不能为空"] },
// off_price: { _errors: ["折扣价不能为空"] },
// sell_quantity: { _errors: ["销量不能为空"] }
// }
// ✅ 也可遍历所有原始错误详情(含完整 path)
console.log(result.error.issues);
// [
// { path: ["sizes", 0, "price"], message: "价格不能为空" },
// { path: ["sizes", 0, "off_price"], message: "折扣价不能为空" },
// ...
// ]
}⚠️ 注意事项:
- z.string().nonempty() 是推荐写法(比 z.string().min(1) 更语义清晰且错误消息更友好);
- 若需前端直接消费错误结构,format() 返回的对象可直接映射为表单控件的 name="sizes[0].price" 对应的错误提示;
- 避免在 schema 中过度使用 .strict(),除非严格禁止额外字段——它不影响错误粒度,但可能掩盖调试线索;
- 如需自定义错误聚合逻辑(例如合并同级多个错误为一条),可基于 error.issues 数组手动实现,format() 本身不支持插件化定制。
总结:flatten() 适用于简单表单级错误展示,而 format() 才是处理复杂嵌套结构(如数组+对象)错误的正确选择。通过其返回的嵌套对象,你能精准定位到 sizes[0].price 等任意深度字段的验证失败原因,大幅提升表单反馈体验与调试效率。










