Joi是否有「not」校验概念?如何不罗列类型就禁止字段值为对象?
关于Joi实现「字段值禁止为对象类型」的问题说明
你之前的方法失效的核心原因
你对any.not()/any.disallow()的作用判断是准确的:
- 这个方法本身是值层面的匹配规则,校验逻辑为「传入的字段值,不能和括号中传入的具体字面量完全相等」
- 它本身不支持基于Schema规则做类型层面的反向匹配:当你在括号内传入
Joi.object()这个Schema实例时,方法只会把这个Schema实例当成一个需要被排除的“具体值”来做比对,根本不会触发“判断字段值是不是对象类型”的逻辑,自然达不到你要的校验效果。
不需要逐一罗列允许的原始类型的实现方案
你可以不用枚举所有字符串、数字、布尔值等允许的原始类型,直接从值的类型维度做拦截:
- 利用Joi的自定义规则能力,直接拦截所有非原始的对象类值即可,代码示例:
import Joi from 'joi' // 可复用的「仅允许原始类型值」校验规则 const allowPrimitiveOnly = Joi.any().custom((value, helpers) => { // 拦截所有typeof为object的非原始值(null是合法的JSON原始类型,需要单独排除) // 该判断逻辑完全匹配JSON解析的取值范围,不会出现误拦,因为JSON本身不会生成函数、Date实例等特殊对象类型 if (value !== null && typeof value === 'object') { return helpers.error('any.invalid') } return value }, '不允许传入对象/数组类型的字段值') const schema = Joi.object({ myKey: allowPrimitiveOnly })
- 上述规则可以自动拦截普通纯对象、数组等所有非原始类型的字段值,不需要逐一枚举所有允许的原始类型:
- 合法值示例:字符串、数字、布尔值、null都会正常通过校验
- 非法值示例:普通纯对象、数组都会被拦截报错
补充说明
如果不希望写自定义校验逻辑,也可以用Joi的内置类型做白名单校验,但这种方式需要逐一罗列允许的原始类型,和你想要减少罗列代码的需求匹配度较低:
// 白名单方式的实现,需要手动枚举所有允许的原始类型 const allowPrimitiveOnly = Joi.alternatives( Joi.string(), Joi.number(), Joi.boolean(), Joi.valid(null) )
内容的提问来源于stack exchange,提问作者slifty
相关产品推荐
相关产品推荐

