使用Zod编写decode函数时的类型错误及通用实现问询
问题与解决方案
问题描述
我尝试编写一个decode函数,接收Zod schema与unknown类型输入,同时支持输入验证及Zod编解码器输入输出类型不同时的转换。
尝试的实现代码:
import { ZodSchema, z } from 'zod' const DateFromString = z.string().transform(input => new Date(input)) const Event = z.object({ timestamp: DateFromString }) const decode = <T>(schema: ZodSchema<T>, data: unknown): T => schema.parse(data) const { timestamp } = decode(Event, { timestamp: '2024-01-01' })
出现类型错误:
The types of '_input.timestamp' are incompatible between these types.
Type 'string' is not assignable to type 'Date'.(2345)
需求是修复该类型错误,同时确保最后一行的timestamp变量为Date类型;另外希望仅定义一个通用的decode函数,而非为不同类型的schema(如Object、Array、Union)重复实现多个函数(如下示例):
import { ZodArray, ZodObject, ZodRawShape, ZodUnion, ZodUnionOptions } from 'zod' const decodeObject = <T extends ZodRawShape>(schema: ZodObject<T>, data: unknown) => schema.parse(data) const decodeArray = <T extends ZodRawShape>(schema: ZodArray<ZodObject<T>>, data: unknown) => schema.parse(data) const decodeUnion = <T extends ZodUnionOptions>(schema: ZodUnion<T>, data: unknown) => schema.parse(data)
解决方案
通用decode函数的正确实现
问题出在原函数的泛型定义上:ZodSchema<T>仅指定了schema的输出类型,TypeScript会错误地要求输入data匹配输出类型,而非schema实际接受的输入类型。
改用基于schema本身的泛型,并通过Zod内置的z.infer<S>获取输出类型,即可解决问题:
import { ZodType, z } from 'zod' const DateFromString = z.string().transform(input => new Date(input)) const Event = z.object({ timestamp: DateFromString }) // 通用decode函数,支持所有Zod schema类型 const decode = <S extends ZodType>(schema: S, data: unknown): z.infer<S> => { return schema.parse(data) } // 调用示例:无类型错误,timestamp类型为Date const { timestamp } = decode(Event, { timestamp: '2024-01-01' })
原理说明
- 泛型
S extends ZodType:涵盖所有Zod schema类型(Object、Array、Union等),无需为不同schema类型单独实现函数 z.infer<S>:自动推导schema的输出类型,确保返回值类型正确- 输入
data指定为unknown:符合Zodparse方法的参数要求,同时避免TypeScript错误地将输入与输出类型做强制匹配
这样既解决了类型错误,又实现了单一通用函数的需求,同时保证timestamp最终为Date类型。
内容的提问来源于stack exchange,提问作者Utku Ufuk
相关产品推荐
相关产品推荐

