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

使用Zod的Vite库遇TypeError:无法读取undefined的_parse属性求助

Zod + Vite/Vitest 循环依赖导致 _parse 未定义问题解决

问题描述

开发基于Zod的Vite配置解析库,目录结构与配置对象结构一致,各目录index.ts递归导出当前及子目录内容,根index.ts导出全库。在Vitest测试中调用apiConfigurationSchema.parse({})时抛出错误:TypeError: Cannot read properties of undefined (reading '_parse'),疑似循环依赖导致。需保留分目录的自定义验证函数,不合并所有schema到单个文件。

目录结构

.
├── src
│   ├── api
│   │   ├── dataSources
|   |   |   ├── dataSource
|   |   |   |   ├── following
|   |   |   |   |   ├── computed
|   |   |   |   |   |   ├── followingComputedDataSourceConfigurationSchema.ts ( 继承 dataSourceConfigurationSchema )
│   │   │   |   |   |   └── index.ts
|   |   |   |   |   ├── entity
|   |   |   |   |   |   ├── followingEntityDataSourceConfigurationSchema.ts ( 继承 leadingDataSourceConfigurationSchema )
│   │   │   |   |   |   └── index.ts
│   │   │   |   |   └── index.ts
|   |   |   |   ├── leading
|   |   |   |   |   ├── leadingDataSourceConfigurationSchema.ts ( 继承 dataSourceConfigurationSchema )
│   │   │   |   |   └── index.ts
|   |   |   |   ├── dataSourceConfigurationSchema.ts ( 基础 schema )
│   │   |   |   └── index.ts
|   |   |   ├── dataSourcesConfigurationSchema.ts ( 要求包含 leading 和 followings 数组 )
│   |   |   └── index.ts
|   |   ├── apiConfigurationSchema.ts ( 要求包含 dataSources )
│   │   └── index.ts
│   └── index.ts 
└── test
    └── basic.test.ts

测试代码

it('fails.', () => {
  expect(() => apiConfigurationSchema.parse({})).not.toThrow();
});

解决方案

1. 用 Zod z.lazy() 延迟解析schema

在存在循环引用的schema定义中,用z.lazy()包裹依赖的schema,延迟其解析时机到第一次调用parse时,避免初始化顺序问题:

// followingEntityDataSourceConfigurationSchema.ts
import { z } from 'zod';
import { leadingDataSourceConfigurationSchema } from '../leading';
import { dataSourceConfigurationSchema } from '../../dataSourceConfigurationSchema';

export const followingEntityDataSourceConfigurationSchema = z.object({
  // 自定义字段
}).extends(z.lazy(() => dataSourceConfigurationSchema))
  .extend({
    // 如果需要引用leading schema的字段,同样用lazy
    leadingConfig: z.lazy(() => leadingDataSourceConfigurationSchema).optional()
  });

2. 重构目录index.ts的导出逻辑

停止递归导出所有子目录内容,让每个目录的index.ts只导出当前目录的核心schema,需要子模块schema时直接从对应路径导入,避免形成循环导入链:

  • 例如src/api/dataSources/dataSource/index.ts仅导出dataSourceConfigurationSchema,不导出following/leading目录内容
  • 引用followingComputedDataSourceConfigurationSchema时,直接从../dataSource/following/computed路径导入,而非通过父目录index间接导入

3. 区分类型导入与值导入

如果仅需要schema的TypeScript类型而非实际schema对象,使用类型导入避免引入值变量:

// 只导入类型,不参与值的依赖链
import type { LeadingDataSourceConfiguration } from '../leading/leadingDataSourceConfigurationSchema';

4. 调整schema继承关系

检查循环依赖的继承链,比如followingEntityDataSourceConfigurationSchema继承leadingDataSourceConfigurationSchema的场景,可改为直接继承基础schema,再单独引入leading的字段类型,减少值层面的循环引用。

5. 调整Vitest配置

在vitest.config.ts中将Zod设为内联依赖,或开启循环依赖警告辅助定位:

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    deps: {
      inline: ['zod'],
    },
    logLevel: 'warn', // 开启警告便于定位循环依赖
  },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:17:49