如何用Joi确保两个日期字段至少一个为有效日期?
解决Joi验证两个日期字段至少一个为有效日期的问题
你需要的是允许字段为空字符串,但必须保证至少一个字段是有效日期的验证规则,之前的两种方案都有缺陷,这里提供两种直接用Joi实现的方案:
方案一:自定义对象验证(推荐)
通过custom方法在对象级别做全局验证,既允许字段为空,又能确保至少一个是有效日期:
const schema = Joi.object({ date1: Joi.date().allow(null, ""), date2: Joi.date().allow(null, "") }).custom((value, helpers) => { // 检查date1是否为有效日期(非空且通过日期验证) const date1IsValid = value.date1 !== "" && value.date1 !== null && Joi.date().validate(value.date1).error === undefined; // 检查date2是否为有效日期 const date2IsValid = value.date2 !== "" && value.date2 !== null && Joi.date().validate(value.date2).error === undefined; if (!date1IsValid && !date2IsValid) { return helpers.error('object.invalid', { message: 'date1和date2中至少有一个必须是有效日期' }); } return value; }, '至少一个有效日期验证');
这个方案的逻辑:
- 每个字段先允许空字符串或null
- 在对象验证阶段,判断两个字段是否都不是有效日期(空/无效格式),如果是则抛出错误
- 只要有一个字段是有效日期,就通过验证
方案二:使用alternatives组合多种场景
通过alternatives.try枚举所有合法的场景(date1有效、date2有效、两者都有效):
const schema = Joi.alternatives().try( // 场景1:date1有效,date2可空 Joi.object({ date1: Joi.date().required(), date2: Joi.date().allow(null, "") }), // 场景2:date2有效,date1可空 Joi.object({ date2: Joi.date().required(), date1: Joi.date().allow(null, "") }), // 场景3:两者都有效 Joi.object({ date1: Joi.date().required(), date2: Joi.date().required() }) );
这个方案通过枚举所有合法情况,直接拒绝双空或双无效的场景。
为什么之前的方案不行?
- 第一种方案未允许空字符串,导致单字段有效+另一字段为空时,空字段会触发日期格式错误
- 第二种方案允许空字符串后,
.or()会将空字符串视为“符合字段规则”的值,因此双空场景会被错误地通过验证
内容的提问来源于stack exchange,提问作者Randall
相关产品推荐
相关产品推荐

