
本文详解如何使用 yup 的自定义校验规则,实现“仅当某字段为 true 时,才要求其余多个布尔字段中至少一个为 true”的条件性验证逻辑。
本文详解如何使用 yup 的自定义校验规则,实现“仅当某字段为 true 时,才要求其余多个布尔字段中至少一个为 true”的条件性验证逻辑。
在构建表单验证逻辑时,常需处理依赖型约束(conditional validation)——即某个字段的校验规则取决于其他字段的值。Yup 本身不直接支持跨字段的条件必填(如 when() 无法原生作用于多个目标字段),但可通过 .test() 方法灵活实现此类高级校验。
以下是一个典型场景:用户需先选择是否启用分类(hasCategory: boolean),若启用(true),则必须从 cat1–cat4 四个布尔选项中至少勾选一项;若未启用(false),则所有分类字段均无需校验。
✅ 正确实现方式:使用 .test() 进行对象级条件校验
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', // test name (used for error identification)
'At least one category must be true', // error message
(value) => {
// 条件跳过:当 hasCategory 为 false 时,校验自动通过
if (!value.hasCategory) return true;
// 检查至少一个分类为 true(使用位或 | 提升可读性与短路效率)
return value.cat1 || value.cat2 || value.cat3 || value.cat4;
}
);? 技巧说明:此处 .test() 应用在 Yup.object() 上,而非单个字段,因此可安全访问整个表单值对象(value),实现跨字段逻辑判断。这是处理“全局条件约束”的标准模式。
⚠️ 注意事项与最佳实践
- 避免滥用 when() 嵌套:Yup.boolean().when(...) 适用于单字段条件修饰(如 cat1 是否必填),但无法简洁表达“hasCategory === true 时要求 cat1–cat4 中任一为真”——此时 .test() 更清晰、可控。
- 错误提示精准定位:该测试的 name 设为 'hasCategory',配合统一错误消息,便于在 Formik 或 React Hook Form 中准确映射到对应 UI 区域(例如显示在 hasCategory 字段下方或独立校验区块)。
- 性能与可维护性:逻辑集中于一处,后续若扩展为 cat5、cat6,只需在条件表达式中追加即可,无需新增字段 schema 或重复配置。
-
类型安全提示(TypeScript 用户):建议为 value 添加类型断言,提升开发体验:
.test('hasCategory', '...', (value) => { const v = value as { hasCategory: boolean; cat1: boolean; cat2: boolean; cat3: boolean; cat4: boolean }; if (!v.hasCategory) return true; return v.cat1 || v.cat2 || v.cat3 || v.cat4; })
✅ 总结
当 Yup 内置 API(如 when、oneOf、requiredWhen)无法覆盖复杂业务约束时,.test() 是最可靠、最语义化的扩展入口。它将验证逻辑从“字段声明式”升级为“对象行为式”,赋予开发者完全的控制权。本例不仅解决了“有条件地要求至少一个布尔值为真”的具体需求,更提供了一种可复用于类似场景(如:启用开关 → 强制填写关联输入框/下拉项)的通用范式。









