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

Zod递归Schema构建:含特殊叶子节点的树形结构报错unrecognized_keys

Zod 树形节点类型的正确实现方案

需求说明

需要在Zod中实现以下TypeScript树形结构类型:

type CommonParentData = {
    id: string,
    name: string,
    // 其他公共属性...
}

type SpecificChild = CommonParentData & {
    specific_property1: string
    specific_property2: number
    children: []
}

type Parent = CommonParentData & {
    children: Array<CommonParentData | SpecificChild>
}

该结构中,所有节点共享公共属性,仅叶子节点拥有专属额外属性,且叶子节点的children为空数组。

问题重现

之前的实现尝试中,出现**无法识别的键(unrecognized_keys)**错误,原因是递归schema仅基于公共属性扩展,未包含叶子节点的专属属性,且使用strictObject时会拦截未定义的额外字段。原尝试代码:

const commonSchema = z.strictObject({
    id: z.string(),
    name: z.string(),
    // 其他公共属性...
});

const childSchema = commonSchema.merge(
    z.strictObject({
        specific_property1: z.string(),
        specific_property2: z.number(),
        children: z.tuple([]),
    }),
);

type Child = z.infer<typeof childSchema>;

type Parent = z.infer<typeof commonSchema> & {
    children: Array<Child | Parent>;
};

const schema: z.ZodType<Parent> = commonSchema.extend({
   children: z.lazy(() => schema.array()),
});

正确实现方案

通过**联合类型(Union)**将父节点与叶子节点的schema合并,利用Zod的自动类型匹配能力处理递归结构,同时保留严格校验规则:

import { z } from "zod";

// 定义公共字段的基础schema
const commonFields = z.object({
  id: z.string(),
  name: z.string(),
  // 补充其他公共属性
});

// 叶子节点schema:公共字段 + 专属属性 + 空children元组
const leafNodeSchema = commonFields.merge(
  z.strictObject({
    specific_property1: z.string(),
    specific_property2: z.number(),
    children: z.tuple([]),
  })
);

// 先声明递归节点的类型引用
type TreeNode = z.infer<typeof nodeSchema>;

// 父节点schema:公共字段 + 子节点数组(支持递归的节点类型)
const parentNodeSchema = commonFields.merge(
  z.strictObject({
    children: z.lazy(() => nodeSchema.array()),
  })
);

// 节点联合schema:同时支持父节点和叶子节点
const nodeSchema = z.union([parentNodeSchema, leafNodeSchema]);

// 导出对应的TypeScript类型
type LeafNode = z.infer<typeof leafNodeSchema>;
type ParentNode = z.infer<typeof parentNodeSchema>;

关键说明

  1. 联合类型匹配:Zod会根据children字段的类型(空元组 vs 节点数组)自动匹配对应的schema,不会触发额外字段错误。
  2. 递归处理:使用z.lazy()延迟引用nodeSchema,解决递归类型的定义顺序问题。
  3. 严格模式保留:叶子节点和父节点单独使用strictObject,确保各自字段的严格校验,同时联合类型的匹配逻辑会避免跨类型的字段校验冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 00:32:43