使用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
相关产品推荐
相关产品推荐

