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

使用Zod的superRefine时如何获取Schema的shape属性?

问题解决:Zod使用superRefine后无法内省Schema的shape属性

为什么superRefine会改变Schema类型?

Zod的superRefine方法不会修改原有的ZodObject实例,而是返回一个全新的ZodEffects对象——它相当于一个"包装器",把原Schema和自定义验证逻辑整合在一起。所以原本的z.AnyZodObject类型会变成z.ZodEffects<z.AnyZodObject>,而ZodEffects并没有shape属性,这就是你无法继续内省的原因。

解决方案:提取被包裹的原始Schema

Zod为ZodEffects提供了官方的unwrap()方法,可获取它内部包裹的原始Schema。如果存在多层ZodEffects(比如多次调用superRefine),可以递归解开所有包装,直到拿到底层的ZodObject。

第一步:编写工具函数提取原始对象Schema

import { z } from "zod";

function getBaseObjectSchema(schema: z.ZodTypeAny): z.ZodObject<any> {
  let currentSchema = schema;
  // 递归解开所有ZodEffects包装
  while (currentSchema instanceof z.ZodEffects) {
    currentSchema = currentSchema.unwrap();
  }
  // 确保最终拿到的是ZodObject
  if (!(currentSchema instanceof z.ZodObject)) {
    throw new Error("传入的Schema并非基于ZodObject");
  }
  return currentSchema;
}

第二步:修改handleForm函数适配ZodEffects

把参数类型从z.AnyZodObject放宽到z.ZodTypeAny,先提取原始Schema再进行内省:

import { z } from "zod";
import { React } from "react";

export const handleForm =
  (schema: z.ZodTypeAny) =>
  (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    const data = new FormData(event.currentTarget);
    // 获取底层的ZodObject
    const baseSchema = getBaseObjectSchema(schema);

    const keys = Object.keys(baseSchema.shape) as Array<keyof z.infer<typeof schema>>;
    // 基于原始Schema判断数组类型键
    const arrayKeys = keys.filter(key => baseSchema.shape[key] instanceof z.ZodArray);

    const values = Object.fromEntries(
      Array.from(data.keys()).map(key => [
        key,
        arrayKeys.includes(key as any) ? data.getAll(key) : data.get(key)
      ])
    );

    // 后续仍可用原schema验证数据,ZodEffects会包含所有验证逻辑
    const validatedData = schema.parse(values);
  };

关于内部API的说明

你提到的_input、_output、_def属于Zod的内部未公开API,官方不保证这些属性的稳定性,版本更新时可能被修改或移除,因此不建议在生产代码中使用,优先使用官方提供的unwrap()方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 10:20:19