如何在Zod Schema中自定义数字校验的错误提示?
解决Zod + React Hook Form数字输入框空值错误提示问题
问题核心在于你设置了{ valueAsNumber: true },输入框为空时React Hook Form会把空值转为NaN,而Zod的z.number()校验失败时会抛出默认的「Expected number, received NaN」错误,且z.number()本身不支持直接传入自定义错误消息。
这里提供两种简洁的解决方式:
方法一:使用z.coerce.number()(推荐)
z.coerce.number()会自动尝试将输入值转为数字,同时支持通过invalid_type_error参数自定义类型转换失败时的错误提示,完美覆盖空值转NaN的场景。
修改后的Zod Schema代码:
import { z } from "zod"; export const newTransactionSchema = z.object({ title: z .string() .min(1, "Title Must Be Atleast 1 Character") .max(10, "Title Must Be No Longer Than 10 Characters"), // 替换原number()为coerce.number()并设置自定义错误 amountSpent: z.coerce.number({ invalid_type_error: "请输入有效的金额数字", // 空值时的自定义提示 }).positive("Please Enter An Expense Greater Than 0"), description: z .string() .min(8, "Description Must Be At Least 8 Characters") .max(25, "Description Must Be No Longer Than 25 Characters"), }); export type TNewTransaction = z.infer<typeof newTransactionSchema>;
输入框代码可保持不变,也可以去掉valueAsNumber: true(因为coerce.number()已处理类型转换):
<label htmlFor="amountSpent">Amount Spent</label> <input type="number" className="mt-2 rounded-md border border-[#3a3a3a] bg-[#0A0A0A] px-2 py-1 text-white outline-none focus:border-[#3a3a3a] focus:ring-2 focus:ring-[#3a3a3a] focus:ring-offset-2 focus:ring-offset-black" id="amountSpent" {...register("amountSpent")} // 可去掉valueAsNumber配置 /> <span className="mb-3 font-medium text-rose-500"> {errors?.amountSpent?.message} </span>
方法二:预处理空值 + 自定义校验
如果不想用coerce,可以通过z.preprocess先把空值转为undefined,再结合refine强制要求输入值存在:
amountSpent: z.preprocess( (val) => { // 空字符串转为undefined if (val === "") return undefined; // 其他值尝试转换为数字 return Number(val); }, z.number() .positive("Please Enter An Expense Greater Than 0") .optional() .refine((val) => val !== undefined, "请输入金额") )
这种方式稍显繁琐,但适合需要更复杂预处理逻辑的场景。
内容的提问来源于stack exchange,提问作者itsjames212
相关产品推荐
相关产品推荐

