Joi中alternatives().conditional()与any().when()的差异问询
alternatives.conditional与any.when的区别及验证差异场景 基础定义回顾
alternatives.conditional:添加基于其他键值或当前值的条件备选schema类型any.when:添加验证期间评估的条件,并在应用schema前修改值或叠加验证规则
核心差异
两者最本质的区别是逻辑执行方式:
alternatives.conditional:多选一逻辑——按顺序匹配条件,只要第一个条件满足,就使用对应的schema,后续所有条件直接忽略。any.when:叠加复合逻辑——所有满足条件的规则都会被应用,最终是多个匹配schema的复合验证。
验证结果不同的场景示例
场景1:多个条件同时满足
假设我们需要根据对象的type字段和value的长度设置验证规则:
使用alternatives.conditional的情况
const schema = Joi.object({ type: Joi.string().valid('a', 'b'), value: Joi.alternatives().conditional('type', { is: 'a', then: Joi.string().min(3), otherwise: Joi.conditional(Joi.string().length(2), { is: true, then: Joi.string().uppercase() }) }) });
当输入{ type: 'a', value: 'AB' }时,第一个条件(type为'a')匹配,直接应用min(3)规则,value长度仅2,验证失败。后续“长度为2则转大写”的条件完全不会触发。
使用any.when的情况
const schema = Joi.object({ type: Joi.string().valid('a', 'b'), value: Joi.string() .when('type', { is: 'a', then: Joi.string().min(3) }) .when(Joi.string().length(2), { is: true, then: Joi.string().uppercase() }) });
同样输入{ type: 'a', value: 'AB' },两个when的条件都满足:type是'a',且value长度为2。此时会同时应用min(3)和uppercase()规则,value因长度不够验证失败;如果输入{ type: 'b', value: 'ab' },第一个条件不满足,第二个条件满足,value会被转为大写后验证通过。
场景2:条件存在包含关系
比如我们有规则:如果role是admin,允许任意长度的字符串;如果role是user,字符串长度至少5;同时如果字符串长度超过10,必须包含大写字母。
使用alternatives.conditional的情况
const schema = Joi.object({ role: Joi.string().valid('admin', 'user'), content: Joi.alternatives().conditional('role', { is: 'admin', then: Joi.string(), otherwise: Joi.alternatives().conditional(Joi.string().length(10), { is: { $gt: 10 }, then: Joi.string().uppercase(), otherwise: Joi.string().min(5) }) }) });
当输入{ role: 'user', content: 'abcdefghijk' }(长度11),第一个条件(role为user)触发,进入第二个条件判断,长度超过10,应用uppercase()规则。此时如果content是小写,验证失败;但如果role是admin,不管长度和大小写都直接通过,后续条件不会被检查。
使用any.when的情况
const schema = Joi.object({ role: Joi.string().valid('admin', 'user'), content: Joi.string() .when('role', { is: 'user', then: Joi.string().min(5) }) .when(Joi.string().length(10), { is: { $gt: 10 }, then: Joi.string().uppercase() }) });
当输入{ role: 'user', content: 'abcdefghijk' },两个条件都满足:role是user,且长度超过10。所以会同时应用min(5)和uppercase()规则,content需要同时满足长度≥5且包含大写(或被转大写),验证逻辑是叠加的。
对官方说明的通俗解释
官方提到的:
alternatives.conditional()与any.when()不同。使用any.when()时,最终会得到所有匹配条件的复合 schema,而alternatives.conditional()将使用第一个匹配的 schema,忽略其他条件语句。
翻译成直白的话:
any.when是“满足几个条件就加几个规则”,所有符合条件的规则都会凑在一起验证,相当于逻辑与(AND)的叠加。alternatives.conditional是“找到第一个符合的条件就用对应的规则,后面的都不管”,相当于逻辑或(OR)的单选,只取第一个匹配项。
适用场景总结
- 选
alternatives.conditional:当你需要互斥的规则分支,比如一个值只能属于某一类验证逻辑,不同分支之间不会同时生效。 - 选
any.when:当你需要叠加的规则约束,比如满足多个条件时,每个条件对应的验证要求都必须被满足。
内容的提问来源于stack exchange,提问作者Ivan Rubinson

