Ключевое слово anyOf в JSON Schema используется для
описания ситуаций, когда данные должны соответствовать хотя бы одной из
нескольких альтернативных схем. В контексте Ajv этот оператор является
одним из основных инструментов построения гибких и расширяемых
валидационных правил, особенно при работе с полиморфными структурами
данных.
anyOf принимает массив схем и требует, чтобы входные
данные прошли валидацию хотя бы по одной из них.
Формально:
Это принципиально отличает anyOf от:
allOf — должны пройти все схемыoneOf — должна пройти ровно одна схемаnot — ни одна схема не должна подходить{
"anyOf": [
{ "type": "string" },
{ "type": "number" }
]
}
Такое описание означает, что значение может быть строкой или числом.
В Ajv это транслируется в проверку альтернативных валидаторов, каждый из которых выполняется независимо.
import Ajv from "ajv";
const ajv = new Ajv();
const schema = {
anyOf: [
{ type: "string" },
{ type: "number" }
]
};
const validate = ajv.compile(schema);
validate("hello"); // true
validate(42); // true
validate(true); // false
Логика проверки строится на последовательной попытке применить каждую схему.
anyOf особенно полезен при описании объектов с разной
структурой.
const schema = {
anyOf: [
{
type: "object",
properties: {
type: { const: "user" },
name: { type: "string" }
},
required: ["type", "name"]
},
{
type: "object",
properties: {
type: { const: "admin" },
permissions: { type: "array", items: { type: "string" } }
},
required: ["type", "permissions"]
}
]
};
В этом случае данные могут описывать либо пользователя, либо администратора.
Типичный сценарий применения — ответы API, где структура зависит от состояния или типа сущности.
const schema = {
anyOf: [
{
type: "object",
properties: {
status: { const: "ok" },
data: { type: "object" }
},
required: ["status", "data"]
},
{
type: "object",
properties: {
status: { const: "error" },
message: { type: "string" }
},
required: ["status", "message"]
}
]
};
Такая модель позволяет формализовать union-типы на уровне JSON Schema без введения дополнительной логики в коде приложения.
Важная особенность anyOf: совпадение нескольких схем не
считается ошибкой.
const schema = {
anyOf: [
{ type: "number", minimum: 0 },
{ type: "number", maximum: 100 }
]
};
Значение 50 удовлетворяет обеим схемам одновременно, но
валидация проходит успешно.
Это поведение важно учитывать при проектировании схем, так как отсутствие ограничения на уникальность совпадений может приводить к неоднозначной интерпретации данных.
anyOf может использоваться рекурсивно, формируя сложные
деревья условий.
const schema = {
anyOf: [
{
type: "object",
properties: {
kind: { const: "A" },
value: { type: "string" }
}
},
{
type: "object",
anyOf: [
{
properties: {
kind: { const: "B" },
value: { type: "number" }
}
},
{
properties: {
kind: { const: "C" },
value: { type: "boolean" }
}
}
]
}
]
};
Подобные конструкции позволяют моделировать сложные доменные правила без перехода к императивной проверке.
Хотя anyOf и oneOf часто используются в
схожих сценариях, их семантика различается принципиально:
anyOf допускает пересечение схемoneOf требует строгой уникальности совпаденияВ Ajv это влияет на поведение ошибок: при oneOf наличие
нескольких совпадений приводит к провалу валидации, тогда как
anyOf продолжает считать результат корректным.
Комбинация anyOf с required,
additionalProperties, enum и
const позволяет создавать точные дискриминируемые
структуры.
const schema = {
anyOf: [
{
type: "object",
required: ["kind"],
properties: {
kind: { const: "text" },
value: { type: "string" }
}
},
{
type: "object",
required: ["kind"],
properties: {
kind: { const: "number" },
value: { type: "number" }
}
}
]
};
Здесь поле kind выступает дискриминатором, а
anyOf — механизмом выбора подходящей ветки схемы.
При использовании anyOf валидатор выполняет проверку
каждой вложенной схемы до нахождения совпадения или до завершения
списка. Это означает:
В Ajv оптимизация часто достигается за счёт:
const/enum)anyOfЧастые проблемы при использовании anyOf:
Такие ошибки приводят к неоднозначной валидации и усложняют сопровождение схем.
anyOf может применяться внутри массивов для описания
разнородных коллекций:
const schema = {
type: "array",
items: {
anyOf: [
{ type: "string" },
{ type: "number" },
{
type: "object",
properties: {
id: { type: "number" }
},
required: ["id"]
}
]
}
};
Такая конструкция часто используется при обработке событийных потоков или логов, где элементы массива могут иметь различную природу.
anyOf в экосистеме JSON Schema и Ajv выполняет роль
базового инструмента для выражения:
Грамотное применение позволяет перенести значительную часть логики проверки данных на уровень схемы, снижая зависимость от прикладного кода.