如何为含动态字段的路径创建TypeScript类型守卫
Zod联合类型Schema的类型守卫实现方案
场景说明
现有Schema类型的schema字段支持两种取值格式:
- 直接存储
ZodTypeAny类型的Zod schema实例 - 存储以
Key联合类型值为键、对应Zod schema实例为值的键值对映射对象
直接对该字段做下标取值时,TypeScript会报类型错误,需要通过类型守卫完成类型收窄。
完整实现代码
import * as z from 'zod'; import type { ZodTypeAny } from 'zod' type Key = 'test' | 'test2' | 'test3' // 拆分两种schema类型,提升可读性 type SingleSchema = ZodTypeAny; type SchemaMap = Partial<Record<Key, ZodTypeAny>>; type Schema = { schema?: SingleSchema | SchemaMap } /** * 类型守卫:判断入参是否为单个Zod schema实例 * 判断依据:Zod实例自带safeParse/parse等专属方法,普通映射对象不存在该属性 */ const isSingleSchema = (value: unknown): value is SingleSchema => { return typeof value === 'object' && value !== null && 'safeParse' in value && typeof (value as SingleSchema).safeParse === 'function'; }; const userSchema = z.object({ name: z.string(), email: z.string(), }); const getSchema = (key: Key, path: Schema): ZodTypeAny | undefined => { const schemaConfig = path.schema; if (!schemaConfig) return undefined; // 收窄为单个schema场景,直接返回 if (isSingleSchema(schemaConfig)) { return schemaConfig; } // 剩余分支TS自动收窄为SchemaMap类型,按键取值即可 return schemaConfig[key]; } // 测试调用,类型校验完全正常 getSchema('test', { schema: {'test': userSchema} }); getSchema('test', { schema: userSchema });
注意事项
不要通过「对象是否包含Key类型的键」做类型判断:SchemaMap的所有键都是可选属性,空对象
{}也是合法的SchemaMap值,这种判断逻辑会出现误判。基于Zod实例内置特征的判断方式稳定性最高。
内容的提问来源于stack exchange,提问作者DevOverflow
相关产品推荐
相关产品推荐

