如何在Zod解析前将对象转换为数组?
解决Zod适配单个对象/数组混合返回的问题
问题场景
外部API端点的fields字段存在两种返回格式:
- 字段数量为1时,返回单个对象:
{ "fields": { "fullName": "fieldFullname", "type": "fieldType" } }
- 字段数量多于1时,返回对象数组:
{ "fields": [ { "fullName": "fieldFullname", "type": "fieldType" }, { "fullName": "fieldFullname", "type": "fieldType" } ] }
原Zod Schema仅支持数组类型,导致单个对象返回时抛出类型错误:
{ "code": "invalid_type", "expected": "array", "received": "object", "path": [], "message": "Expected array, received object" }
解决方案
可以通过Zod的preprocess或union+transform实现动态类型转换,将单个对象统一转为数组格式,同时完成验证。
方案一:使用preprocess预处理输入
export const metadataFieldSchema = z.object({ fullName: z.string().optional(), type: z.string().optional(), }); export const sObjectMetadataSchema = z.object({ fields: z.preprocess( // 预处理:单个对象转数组,数组保持原样 (input) => Array.isArray(input) ? input : [input], // 验证预处理后的值为metadataFieldSchema数组,支持可选 z.array(metadataFieldSchema).optional() ), });
方案二:使用union兼容两种类型+transform统一格式
export const metadataFieldSchema = z.object({ fullName: z.string().optional(), type: z.string().optional(), }); export const sObjectMetadataSchema = z.object({ fields: z.union([ metadataFieldSchema, z.array(metadataFieldSchema) ]).transform((value) => { // 统一转为数组格式 return Array.isArray(value) ? value : [value]; }).optional(), });
原实现错误原因
之前的transform写法错误在于:回调函数返回了Zod Schema(z.array(metadataFieldSchema).optional()),而transform要求返回验证后的具体值,而非Schema本身。正确逻辑应该是先处理输入结构,再执行验证,或者先兼容两种输入类型再统一转换格式。
内容的提问来源于stack exchange,提问作者xTchan
相关产品推荐
相关产品推荐

