Zod refine参数类型显示与实际值不符引发getTime调用报错
问题原因
Zod的执行顺序是先完成所有验证逻辑(包括refine),再执行transform转换。你在object schema上添加的refine会在字段的transform之前触发,所以此时start和end还是原始字符串——虽然TypeScript会根据schema推断出它们是Date类型,但运行时实际值是字符串,调用getTime()自然会抛出错误。
解决方案
方案一:使用pipe分离转换与验证逻辑
通过pipe将转换后的schema与验证schema串联,确保refine拿到的是转换后的Date对象:
const rawDateSchema = z .string({ required_error: 'expected YYYY-MM-DD', invalid_type_error: 'expected YYYY-MM-DD' }) .regex(/^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$/, { message: 'must be in YYYY-MM-DD format' }); const dateRangeSchema = z.object({ start: rawDateSchema, end: rawDateSchema }) // 先将字符串转换为Date对象 .transform(({ start, end }) => ({ start: new Date(start + 'T00:00:00.000Z'), end: new Date(end + 'T00:00:00.000Z') })) // 通过pipe连接到验证schema,确保refine处理转换后的值 .pipe(z.object({ start: z.date(), end: z.date() }).refine(({ start, end }) => { return end.getTime() >= start.getTime(); }, 'end date must be larger or equal to start date')); const validateStartEndDates = (searchParams: URLSearchParams) => dateRangeSchema.parse({ start: searchParams.get('start'), end: searchParams.get('end') });
方案二:手动拆分解析与验证
先解析得到转换后的Date对象,再单独做日期比较验证,逻辑更直观:
const dateValidator = z .string({ required_error: 'expected YYYY-MM-DD', invalid_type_error: 'expected YYYY-MM-DD' }) .regex(/^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$/, { message: 'must be in YYYY-MM-DD format' }) .transform((v) => new Date(v + 'T00:00:00.000Z')); const validateStartEndDates = (searchParams: URLSearchParams) => { // 先完成转换,拿到Date对象 const { start, end } = z.object({ start: dateValidator, end: dateValidator }).parse({ start: searchParams.get('start'), end: searchParams.get('end') }); // 手动验证日期顺序 if (end.getTime() < start.getTime()) { throw new Error('end date must be larger or equal to start date'); } return { start, end }; };
内容的提问来源于stack exchange,提问作者Sihoon Kim
相关产品推荐
相关产品推荐

