如何结合Zod与已有TypeScript接口实现类型安全的数据转换?
解决方案:结合TypeScript编译时检查与Zod的安全转换
要同时满足生成类型变更时的编译时报错和简化转换逻辑、消除非空断言的需求,可以通过「TypeScript类型约束 + Zod Schema验证+转换」的组合方案实现,具体如下:
实现步骤
1. 依赖安装
确保已安装Zod:
npm install zod
2. 核心代码实现
import { z } from "zod"; // 生成的API类型(无需修改,保持原样) type GeneratedAction = { id: string; description: string; recordsList?: GeneratedRecordsList[]; }; type GeneratedRecordsList = { timestamp: { epochMillis: number }; traceId: string; code?: string; responseTimeMs: number; fullId?: { someId: string; otherId: string }; }; // 定义输入验证+转换的Zod Schema const GeneratedRecordsListSchema = z.object({ timestamp: z.object({ epochMillis: z.number() }), responseTimeMs: z.number(), // 断言可选字段必存在,运行时自动验证 code: z.string().optional().refine(val => val !== undefined, "code字段必须存在"), fullId: z.object({ someId: z.string(), otherId: z.string() }).optional().refine(val => val !== undefined, "fullId字段必须存在"), traceId: z.string() }) .passthrough() // 忽略不需要的多余字段(如traceId) .transform(({ timestamp, responseTimeMs, code, fullId }) => ({ timestamp: timestamp.epochMillis, responseTimeMs, code, someId: fullId.someId, otherId: fullId.otherId })); const GeneratedActionSchema = z.object({ id: z.string(), description: z.string(), recordsList: z.array(GeneratedRecordsListSchema).optional().refine(val => val !== undefined, "recordsList字段必须存在") }) .transform(({ id, description, recordsList }) => ({ id, description, recordsList })); // 从Zod Schema自动推导目标类型,无需手动维护 export type SelfTypedAction = z.infer<typeof GeneratedActionSchema>; export type SelfTypedRecordsList = z.infer<typeof GeneratedRecordsListSchema>; // 转换函数 const convertToObject = (action: GeneratedAction): SelfTypedAction => { return GeneratedActionSchema.parse(action); };
方案优势
编译时类型安全
转换函数的参数严格绑定GeneratedAction类型,一旦生成的API类型发生变更(如字段删除、类型修改),TypeScript会立即在编译阶段报错,和原方案的即时检测能力一致。消除非空断言
通过Zod的refine方法在运行时验证「用户确定存在的可选字段」确实存在,同时Zod的类型推导会自动将这些字段转为必填类型,无需手动添加!非空断言。简洁的转换逻辑
所有结构转换(扁平化、字段映射)都集中在Zod的transform方法中,深层结构的转换可通过嵌套Schema实现,代码更易维护。运行时安全兜底
Zod会自动验证输入数据的结构和类型,若出现不符合预期的数据(如用户以为存在的字段实际缺失),会抛出明确的错误信息,便于调试。
扩展处理
如果需要处理更复杂的深层结构,只需嵌套定义Zod Schema并在transform中对应解析即可;若要给字段设置默认值,可通过Zod的default方法或在transform中使用空值合并运算符(??)实现。
内容的提问来源于stack exchange,提问作者MrMamen
相关产品推荐
相关产品推荐

