React useForm结合Zod配置可选输入遇「Expected string, received nan」错误求助
React useForm + Zod 可选数字输入报错:Expected string, received nan
问题重现
在React useForm中搭配Zod实现可选折扣输入时,明明设置了非必填规则,却始终收到错误提示:Expected string, received nan。
Zod Schema 代码
discount: z .string() .optional() .transform((discount) => discount === "" || discount === undefined ? undefined : parseInt(discount) ) .pipe(z.number().nonnegative().max(100)),
FormInput 组件代码
<FormInput<FormData, InputProps> id="DiscountFormCreateProduct" register={register} rules={{ required: false, valueAsNumber: true }} errors={errors} className="col-span-3" name="discount" labelText="Discount" label="Discount number " Formtype={FormElementType.INPUT} placeholder="Discount(Eg 5%)" isRequired={false} type="number" min={0} max={100} />
问题原因
- 类型不匹配:Zod Schema定义的是
z.string()类型,但useForm的valueAsNumber: true会将输入值强制转为数字。当输入为空时,这个转换会得到NaN,而Zod期望接收string类型,直接触发类型校验错误。 - Transform逻辑失效:空输入时,
valueAsNumber已经把值转成了NaN,导致Zod的transform函数接收到的不是预期的""或undefined,无法按逻辑转为undefined,后续的pipe校验自然失败。
解决方案
方案一:调整Zod Schema适配数字输入(推荐)
因为输入是type="number",直接让Zod处理数字类型,同时兼容空输入产生的NaN:
discount: z .unknown() .transform((val) => { if (val === "" || val === undefined || Number.isNaN(val)) { return undefined; } return typeof val === "number" ? val : parseInt(val); }) .pipe(z.number().nonnegative().max(100).optional()),
或者用Zod的优秀END chart(AD真诚YN费 Events( Default
I的:不对,用更简洁的coerce方法自动处理类型转换:
discount: z.coerce .number() .nonnegative() .max(100) .optional() .transform((val) => Number.isNaN(val) ? undefined : val),
方案二:移除useForm的valueAsNumber,保持字符串输入
去掉register配置里的valueAsNumber: true,让输入值保持string类型,适配原来的Zod Schema逻辑:
<FormInput<FormData, InputProps> // ...其他属性保持不变 rules={{ required: false }} // 移除valueAsNumber配置 />
此时空输入会传递""给Zod,transform函数能正确转为undefined,顺利通过后续的数字校验。
内容的提问来源于stack exchange,提问作者lcsaloon
相关产品推荐
相关产品推荐

