
使用 Joi 的 .min(1) 可替代 .or() 实现“对象中至少存在一个键”的校验需求,避免 .or() 在严格模式下误报必填错误。
使用 joi 的 `.min(1)` 可替代 `.or()` 实现“对象中至少存在一个键”的校验需求,避免 `.or()` 在严格模式下误报必填错误。
在 Joi 中,.or() 方法常被误解为“允许任一字段存在即可”,但实际上它要求至少一个字段必须存在且有效(即不为 undefined、null 或空值),同时默认会对未声明的字段执行严格模式校验(取决于 stripUnknown 和 presence 设置)。更关键的是:.or() 并非用于限制“对象最少含几个键”,而是用于定义字段间的逻辑或关系——当多个字段均被显式传入但均无效时才触发校验失败。因此,当你期望“payload 至少包含列表中的一个字段”,真正语义匹配的 API 是 .min(1)。
✅ 正确做法是使用 .min(1),它明确表示:该对象至少需包含一个已定义的键(且其值不为 undefined):
import * as Joi from 'joi';
export const PAYLOAD = Joi.object({
PUSH_UP: Joi.any(),
INVERTED_ROW: Joi.any(),
DIP: Joi.any(),
CHIN_UP: Joi.any(),
PULL_UP: Joi.any(),
GOBLET_SQUAT: Joi.any(),
BACK_EXTENSION: Joi.any()
}).min(1); // ? 核心:对象至少含 1 个有效键✅ 示例验证通过:
// ✅ 合法:含两个字段
PAYLOAD.validate({
"BACK_EXTENSION": { "reps": 30, "exerciseId": 7 },
"PUSH_UP": { "reps": 1, "exerciseId": 1 }
});
// ✅ 合法:仅含一个字段
PAYLOAD.validate({ "DIP": { "reps": 15, "exerciseId": 3 } });
// ❌ 失败:空对象
PAYLOAD.validate({}); // error: "value must contain at least 1 children"⚠️ 注意事项:
- 不要混用
.or()与.min(1)—— 二者语义不同,.or()更适合如"email OR phone"这类互斥必填场景; - 若需进一步约束“值必须为非空对象/有效结构”,应在各字段内细化校验(例如
Joi.object().required().keys({...})),而非依赖.or(); - 确保未启用
stripUnknown: true且未设置presence: 'required'到单个字段上,否则可能引发意外强制校验。
总结:对于“对象中至少存在一个可选字段”的需求,.min(1) 是简洁、准确、符合 Joi 设计意图的标准解法。

















