如何用Zod实现TypeScript中'Property in keyof Type'结构?
问题:基于已有Zod结构创建同键不同类型的新结构
在原生TypeScript中,我可以通过映射类型快速创建一个与原类型键相同但类型不同的新类型:
type TypeA = { something1: number something2: number ... somethingN: number } type TypeB = { [Property in keyof TypeA]: string }
后续增删键只需修改TypeA即可。但在Zod中,当前写法只能得到第一种类型的结构,无法生成对应TypeB的Zod解析器:
const TypeA = z.object({ something1: z.number(), something2: z.number(), ... somethingN: z.number() }) type TypeA = z.infer<typeof TypeA> type TypeB = { [Property in keyof TypeA]: string } // 没有TypeB对应的Zod结构
请问Zod是否支持遍历键并指定类型,实现类似TS映射类型的逻辑,同时获得两种类型的结构/解析器?
解答
完全可行,你可以通过访问Zod对象的shape属性,动态遍历并替换每个字段的验证规则,生成新的Zod结构。
基础实现方案
直接遍历原Zod对象的shape,将每个字段的schema替换为目标类型(比如z.string()):
import { z } from "zod"; // 定义原Zod结构 const TypeA = z.object({ something1: z.number(), something2: z.number(), // 更多字段... }); type TypeA = z.infer<typeof TypeA>; // 动态生成同键不同类型的Zod结构 const TypeB = z.object( Object.fromEntries( Object.entries(TypeA.shape).map(([key]) => [key, z.string()]) ) ); type TypeB = z.infer<typeof TypeB>;
后续增删TypeA的字段时,TypeB会自动同步更新,无需手动修改。
通用工具函数(复用场景)
如果需要频繁进行这类转换,可以封装一个通用工具函数,支持自定义字段类型映射逻辑:
import { z } from "zod"; function mapZodObject<Original extends z.ZodObject<any>>( original: Original, schemaMapper: (schema: z.ZodTypeAny) => z.ZodTypeAny ): z.ZodObject<{ [K in keyof Original["shape"]]: ReturnType<typeof schemaMapper> }> { return z.object( Object.fromEntries( Object.entries(original.shape).map(([key, schema]) => [key, schemaMapper(schema)]) ) ) as z.ZodObject<{ [K in keyof Original["shape"]]: ReturnType<typeof schemaMapper> }>; } // 使用示例:将TypeA的所有字段转为string类型 const TypeB = mapZodObject(TypeA, () => z.string()); type TypeB = z.infer<typeof TypeB>; // 另一个示例:将所有字段转为可选的boolean类型 const TypeC = mapZodObject(TypeA, (schema) => schema.transform(() => true).optional()); type TypeC = z.infer<typeof TypeC>;
原理说明
Zod的object类型暴露了shape属性,该属性存储了对象所有字段对应的schema。通过Object.entries遍历这个属性,就能批量修改每个字段的验证规则,最终用z.object()包装成新的Zod解析器,同时通过z.infer可以得到对应的TypeScript类型。
内容的提问来源于stack exchange,提问作者zaplec
相关产品推荐
相关产品推荐

