Joi 表单验证时如何动态添加校验规则?

程序员长春 阅读 50

我用 Joi 做前端表单验证,但有个字段的校验规则要根据另一个字段的值动态变化。比如当“用户类型”是“企业”时,“公司名称”才必填。试过在 schema 里用 Joi.when(),但一直报错说方法不存在,是不是我用法不对?

这是我的代码:

const schema = Joi.object({
  userType: Joi.string().valid('individual', 'company').required(),
  companyName: Joi.string().when('userType', {
    is: 'company',
    then: Joi.required(),
    otherwise: Joi.optional()
  })
});
我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
涵菲
涵菲 Lv1
看起来你已经很接近正确的做法了,但遇到了一些小问题。别担心,我来帮你一步步解决这个问题。

第一步是确认你的 Joi 版本。Joi.when() 方法确实存在,但你需要确保使用的是支持这个语法的版本(至少 10.0.0 以上)。如果你用的是老版本,升级一下先。

假设你用的是最新版本,我们来看代码的问题。Joi.when() 需要一个完整的规则定义作为参数,而不是直接调用方法链。让我给你一个修正后的版本:

const schema = Joi.object({
userType: Joi.string().valid('individual', 'company').required(),
companyName: Joi.string().when(Joi.ref('userType'), { // 注意这里要用 Joi.ref()
is: 'company',
then: Joi.string().required(), // 这里要重新定义类型
otherwise: Joi.string().optional()
})
});


这里有几点要注意:
1. 使用 Joi.ref('userType') 来引用其他字段的值
2. 在 then 和 otherwise 分支中都要重新定义字段类型
3. 如果想验证更多复杂逻辑,可以在 when 中嵌套多个条件

原理上,Joi 的 when 方法其实就是个条件判断器。它会先检查目标字段(这里是 userType)的值是否符合某个条件,如果符合条件就应用 then 规则,否则用 otherwise 规则。这和编程中的 if-else 逻辑差不多。

举个更复杂的例子:如果我们还需要验证当用户类型是 "vip" 时也要必填公司名称,可以这样写:

const schema = Joi.object({
userType: Joi.string().valid('individual', 'company', 'vip').required(),
companyName: Joi.string().when(Joi.ref('userType'), {
is: Joi.valid('company', 'vip'), // 多个符合条件
then: Joi.string().required(),
otherwise: Joi.string().optional()
})
});


希望这些解释能帮到你。说实话,表单验证这种东西虽然简单,但要做到灵活确实需要些技巧,慢慢来就好。
点赞
2026-03-31 17:06
西门秋梓
看起来你的用法基本是对的,但 Joi 的 when 语法需要特别注意一些细节。我来帮你优化一下这段代码,这样更清晰也更容易维护。

首先,Joi.when() 需要完整的引用路径,而且 thenotherwise 里面的规则要完整定义。这里有个更优雅的写法:

const schema = Joi.object({
userType: Joi.string().valid('individual', 'company').required(),
companyName: Joi.string().when('userType', {
is: 'company',
then: Joi.string().required(),
otherwise: Joi.string().allow('')
})
});


注意到几个地方:在 thenotherwise 里面都显式定义了 Joi.string(),并且用了 allow('') 来允许空值。这样处理企业用户时能正常校验,而个人用户可以不填这个字段。

有时候这种动态规则确实让人头疼,调试时记得打印出错误信息看看具体问题在哪。希望这能帮到你。
点赞
2026-03-29 20:00