本文目录导读:

- 案例一:合并多个 Schema(最经典)
- 案例二:在子 Schema 中增加更严格的限制(条件细化)
- 案例三:与
if/then配合实现复杂业务规则(进阶用法) - 案例四:TS 类型中的 allOf 对应(组合类型)
- ⚠️ 注意事项(避坑指南)
在 JSON Schema 和 TypeScript 类型系统中,allOf 是一个非常核心的组合关键字,它的逻辑是:所有子 Schema 都必须同时满足(逻辑与)。
由于在 JSON Schema 中,我们无法直接在对象里写两个相同的键名(例如两个 properties),allOf 主要用于合并多个 Schema 约束。
以下是几个最典型的应用场景案例:
合并多个 Schema(最经典)
场景:你有一个基础的“人”的 Schema,还有一个“员工”的 Schema,员工必须同时具备这两个特征。
{
"allOf": [
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"required": ["name"]
},
{
"type": "object",
"properties": {
"employeeId": { "type": "string" },
"department": { "type": "string" }
},
"required": ["employeeId"]
}
]
}
校验结果:
- ✅
{ "name": "张三", "employeeId": "E001" }(合法,两者都满足) - ❌
{ "name": "张三" }(非法,缺少employeeId) - ❌
{ "employeeId": "E001" }(非法,缺少name)
在子 Schema 中增加更严格的限制(条件细化)
场景:你有一个通用的“矩形”定义,但现在要求必须是“正方形”(长宽相等)。
痛点:你不能在一个 JSON 对象中写两个 properties 键。
{
"allOf": [
{
"type": "object",
"properties": {
"width": { "type": "number" },
"height": { "type": "number" }
},
"required": ["width", "height"]
},
{
"properties": {
"width": { "const": 10 },
"height": { "const": 10 }
}
}
]
}
解析:第二个 Schema 相当于是在第一个 Schema 的基础上,强行将 width 和 height 的值锁定为 10。
校验结果:
- ✅
{ "width": 10, "height": 10 }(合法) - ❌
{ "width": 5, "height": 5 }(不满足第二个 Schema 的const约束)
与 if/then 配合实现复杂业务规则(进阶用法)
场景:如果商品是“电子产品”,则必须提供“保修年限”;如果是“食品”,则必须提供“保质期”。
{
"allOf": [
{
"type": "object",
"properties": {
"category": { "enum": ["electronics", "food"] },
"name": { "type": "string" }
},
"required": ["category"]
},
{
"if": {
"properties": { "category": { "const": "electronics" } }
},
"then": {
"required": ["warrantyYears"]
}
},
{
"if": {
"properties": { "category": { "const": "food" } }
},
"then": {
"required": ["expiryDate"]
}
}
]
}
解析:allOf 确保第一个基础结构通过后,后面的两个 if 条件会依次判断。
校验结果:
- ✅
{ "category": "electronics", "name": "手机", "warrantyYears": 2 } - ✅
{ "category": "food", "name": "牛奶", "expiryDate": "2024-01-01" } - ❌
{ "category": "electronics", "name": "手机" }(缺少warrantyYears)
TS 类型中的 allOf 对应(组合类型)
在 TypeScript 中使用 json-schema-to-ts 等库时,allOf 直接映射为交叉类型 &。
type Schema = {
allOf: [
{ properties: { a: { type: 'string' } } },
{ properties: { b: { type: 'number' } } }
]
}
// 解析出的 TS 类型为:
// { a: string } & { b: number }
// 等同于 { a: string; b: number }
⚠️ 注意事项(避坑指南)
- 不能覆盖,只能叠加:
allOf不会像继承一样覆盖父类的属性,如果子 Schema 对width的限制是type: 'string',而父 Schema 限制是type: 'number',那么结果是 两者都要满足,即必须同时是字符串又得是数字(这不可能),会导致永远校验不通过。 - 性能:
allOf会遍历所有子 Schema,如果子 Schema 非常复杂且数量多,校验性能会下降,能只用properties解决的就别用allOf。 - 官方推荐:在 JSON Schema 官方文档中,对于“扩展对象”的场景,更推荐使用
unevaluatedProperties或直接扩展,但在不支持的旧版(Draft-04/06)中,allOf依然是主流方案。
如果你想了解特定场景(例如配合 $ref 引用外部 Schema)的案例,可以告诉我,我可以补充更复杂的嵌套例子。