
本文详解如何使用 Yup 的自定义 .test() 方法,实现依赖型条件验证——当 hasCategory 为 true 时,强制要求 cat1–cat4 中至少一个为 true;否则不校验。代码简洁、语义清晰,适用于动态表单场景。
本文详解如何使用 yup 的自定义 `.test()` 方法,实现依赖型条件验证——当 `hascategory` 为 `true` 时,强制要求 `cat1`–`cat4` 中至少一个为 `true`;否则不校验。代码简洁、语义清晰,适用于动态表单场景。
在构建复杂表单时,常需实现「条件性必填」逻辑:某个主开关(如 hasCategory)开启后,才触发对一组关联字段的校验约束。Yup 原生的 when() 方法虽支持字段间依赖,但对「多字段逻辑或(OR)」的聚合校验支持有限;此时,更灵活、更可控的方式是使用 .test() 定义自定义验证规则。
以下是一个完整、生产就绪的验证 Schema 示例:
import * as Yup from 'yup';
const validationSchema = Yup.object()
.shape({
hasCategory: Yup.boolean().required(
'Yes or No must be selected for special ad category'
),
cat1: Yup.boolean(),
cat2: Yup.boolean(),
cat3: Yup.boolean(),
cat4: Yup.boolean()
})
.test(
'hasCategory', // 测试标识名(用于错误定位和调试)
'At least one category must be true', // 错误提示信息
(value) => {
// 若主开关为 false,则跳过校验,直接通过
if (!value.hasCategory) return true;
// 否则检查任意一个分类是否为 true(短路 OR 更推荐,但布尔值用 | 亦可)
return value.cat1 || value.cat2 || value.cat3 || value.cat4;
}
);✅ 关键说明:
- .test() 作用于整个对象实例(即 value 是整个表单值对象),因此可自由访问所有字段并编写复合逻辑;
- 返回 true 表示校验通过,false 或抛出错误则失败;
- 错误消息将自动绑定到整个表单(若需精准绑定到特定字段,可配合 createError() 手动指定 path,但本例中语义上属于整体逻辑约束,无需细化);
- 使用 || 而非 |(按位或)更符合语义且避免潜在类型隐式转换问题(例如 undefined || true 正确返回 true,而 undefined | true 会转为 0 | 1 === 1,虽结果一致但可读性与健壮性较差)。
⚠️ 注意事项:
确保 cat1–cat4 字段始终为布尔值(true/false)。若可能为 undefined 或字符串,建议先用 .nullable(false).oneOf([true, false]) 显式约束其类型;
-
若未来字段数量动态增加(如支持 N 个分类),可将校验逻辑抽象为工具函数,例如:
const atLeastOneSelected = (...keys) => (value) => { if (!value.hasCategory) return true; return keys.some(key => value[key] === true); }; // 使用:.test('hasCategory', ..., atLeastOneSelected('cat1','cat2','cat3','cat4')) 在 Formik 等表单库中集成时,该 Schema 可直接传入 validationSchema 属性,错误信息将自动注入对应字段或表单级错误对象。
掌握 .test() 是解锁 Yup 高级验证能力的关键一步——它让条件逻辑不再受限于字段层级,真正实现「以业务语义驱动校验」。










