Joi配合react-hook-form校验上传图片时触发读取length属性报错
react-hook-form 搭配 Joi 校验上传图片报错解决方案
报错根因
你遇到的Cannot read properties of undefined (reading 'length')错误,核心是错误使用Joi.object()嵌套规则校验浏览器原生File实例:
- 你当前写的
avatar: Joi.object({type: xxx, size: xxx})规则,默认要求传入值是普通JS对象(plain object),但实际上传拿到的avatar是浏览器原生的File实例,不属于普通对象范畴。 - Joi执行内置object规则校验时,会递归遍历对象的所有内部属性做匹配,而File实例的部分内部属性是不可枚举、访问受保护的,当Joi尝试读取这类属性的
length值做校验时,就会拿到undefined触发类型错误。 - 当你把规则改成空的
Joi.object().unknown(true)时,Joi不会深入递归校验内部属性,仅判断值为对象类型就放行,所以不会触发报错,但也无法实现格式、大小的校验逻辑。
修复方案
不要用嵌套object规则校验File/Blob这类宿主对象,改用Joi.custom()自定义校验逻辑,直接读取File实例的公开属性做判断即可:
export type AvatarForm = { avatar: File; }; // 限制图片最大2MB const MAX_AVATAR_SIZE = 2 * 1024 * 1024; const ALLOWED_IMAGE_TYPES = ["image/png", "image/jpeg"]; export const AvatarSchema = Joi.object<AvatarForm, true>({ avatar: Joi.custom((value, helpers) => { // 校验是否为有效File实例 if (!(value instanceof File)) { return helpers.error("file.invalid", { message: "请上传有效图片文件" }); } // 校验文件格式 if (!ALLOWED_IMAGE_TYPES.includes(value.type)) { return helpers.error("file.type", { message: "仅支持PNG、JPEG格式的图片" }); } // 校验文件大小 if (value.size > MAX_AVATAR_SIZE) { return helpers.error("file.size", { message: "图片大小不能超过2MB" }); } return value; }).required() });
额外排查点
- 检查size字段的规则类型匹配:
File.size是数字类型,如果误写了Joi.string().length()这类字符串专属的校验规则,Joi尝试读取数字值的length属性时也会触发同类报错。 - 确认表单绑定逻辑正确:检查上传组件是否正确将File实例赋值给
avatar字段,如果字段值为null/undefined,Joi读取空值属性时也会抛错,可通过.required()明确字段必填要求。 - 版本兼容校验:如果使用的是7.0以下版本的
@hookform/resolvers/joi,建议升级到最新版本,旧版本resolver在传递File这类特殊对象给Joi时存在序列化bug,会丢失对象属性触发校验异常。
内容的提问来源于stack exchange,提问作者matikowy
相关产品推荐
相关产品推荐

