not для отрицания

Ключевое слово not используется для инверсии схемы. Валидация считается успешной только в том случае, если вложенная схема возвращает ошибку.

Фактически not реализует логическое отрицание:

НЕ соответствует указанной схеме

Базовый синтаксис:

{
  not: {
    // схема
  }
}

Если данные подходят под вложенную схему — проверка проваливается.


Простейший пример

Запрет конкретного значения:

const schema = {
  not: {
    const: 10
  }
}

Проверка:

validate(5)   // true
validate(10)  // false

Логика:

  • 5 не равно 10 → проверка успешна
  • 10 соответствует const: 10not инвертирует результат → ошибка

Проверка типов через not

Запрет строк

const schema = {
  not: {
    type: "string"
  }
}

Результаты:

validate(100)     // true
validate(false)   // true
validate("text")  // false

Запрет чисел

const schema = {
  not: {
    type: "number"
  }
}

Отрицание диапазонов

Запрет отрицательных чисел

const schema = {
  not: {
    type: "number",
    maximum: -1
  }
}

Проверка:

validate(10)   // true
validate(0)    // true
validate(-5)   // false

Использование с required

Запрет наличия свойства

Иногда требуется запретить определённое поле.

const schema = {
  type: "object",

  not: {
    required: ["password"]
  }
}

Проверка:

validate({
  name: "Alex"
})
// true

validate({
  name: "Alex",
  password: "123"
})
// false

Как работает схема:

  • если поле password отсутствует — вложенная схема не проходит
  • not инвертирует результат
  • итоговая валидация успешна

Запрет нескольких полей

const schema = {
  type: "object",

  not: {
    required: ["isAdmin", "role"]
  }
}

Ошибка возникнет только при наличии одновременно:

{
  isAdmin: true,
  role: "admin"
}

not и enum

Исключение значений

const schema = {
  type: "string",

  not: {
    enum: ["admin", "root", "superuser"]
  }
}

Проверка:

validate("user")       // true
validate("admin")      // false
validate("superuser")  // false

Запрет пустой строки

const schema = {
  type: "string",

  not: {
    const: ""
  }
}

Проверка строковых шаблонов

Запрет определённого формата

const schema = {
  type: "string",

  not: {
    pattern: "^test"
  }
}

Ошибка:

"test123"

Успешно:

"prod123"

Запрет email-доменов

const schema = {
  type: "string",
  format: "email",

  not: {
    pattern: "@gmail\\.com$"
  }
}

Работа с массивами

Запрет пустого массива

const schema = {
  type: "array",

  not: {
    maxItems: 0
  }
}

Запрет массива определённой длины

const schema = {
  type: "array",

  not: {
    minItems: 3,
    maxItems: 3
  }
}

Массив из трёх элементов станет недопустимым.


Отрицание структуры объекта

Запрет объекта с конкретной комбинацией полей

const schema = {
  type: "object",

  not: {
    properties: {
      type: {
        const: "guest"
      },
      permissions: {
        type: "array"
      }
    },

    required: ["type", "permissions"]
  }
}

Ошибка:

{
  type: "guest",
  permissions: ["write"]
}

Комбинирование с allOf

Последовательные ограничения

const schema = {
  allOf: [
    {
      type: "number"
    },

    {
      not: {
        multipleOf: 2
      }
    }
  ]
}

Допустимы только нечётные числа.

Проверка:

validate(3) // true
validate(4) // false

Комбинирование с anyOf

Запрет одного из вариантов

const schema = {
  anyOf: [
    {
      type: "string"
    },

    {
      type: "number"
    }
  ],

  not: {
    const: 0
  }
}

Разрешены строки и числа, кроме 0.


Комбинирование с oneOf

const schema = {
  oneOf: [
    {
      type: "string"
    },

    {
      type: "number"
    }
  ],

  not: {
    type: "boolean"
  }
}

Инверсия сложной схемы

not может содержать полноценную вложенную схему любой сложности.

const schema = {
  not: {
    type: "object",

    properties: {
      role: {
        const: "admin"
      },

      active: {
        const: false
      }
    },

    required: ["role", "active"]
  }
}

Ошибка:

{
  role: "admin",
  active: false
}

Использование с if/then/else

Запрет условий

const schema = {
  if: {
    properties: {
      age: {
        minimum: 18
      }
    }
  },

  then: {
    not: {
      required: ["parentPermission"]
    }
  }
}

Логика:

  • если возраст 18+
  • поле parentPermission запрещено

Практический пример: валидация пользователя

const schema = {
  type: "object",

  properties: {
    login: {
      type: "string"
    },

    password: {
      type: "string"
    },

    role: {
      type: "string"
    }
  },

  required: ["login", "password"],

  not: {
    properties: {
      login: {
        const: "root"
      },

      role: {
        const: "guest"
      }
    },

    required: ["login", "role"]
  }
}

Недопустимо:

{
  login: "root",
  password: "123",
  role: "guest"
}

Пример с Ajv

Установка

npm install ajv

Базовая проверка

const Ajv = require("ajv")

const ajv = new Ajv()

const schema = {
  not: {
    type: "null"
  }
}

const validate = ajv.compile(schema)

console.log(validate(null))
console.log(validate(123))

Результат:

false
true

Ошибки валидации

Пример:

const schema = {
  not: {
    const: 5
  }
}

Ошибка:

[
  {
    instancePath: "",
    schemaPath: "#/not",
    keyword: "not",
    params: {},
    message: "must NOT be valid"
  }
]

Главное сообщение:

must NOT be valid

Особенности not

Вложенная схема должна быть полностью валидной

Важно понимать принцип работы.

Пример:

{
  not: {
    type: "object",
    required: ["name"]
  }
}

Данные:

5

Почему проверка успешна:

  • число 5 не является объектом
  • вложенная схема не проходит
  • not инвертирует результат
  • итог — успешно

Частая ошибка

Неверная схема:

{
  not: {
    required: ["name"]
  }
}

Проблема:

  • required применяется только к объектам
  • остальные типы автоматически проходят проверку

Правильнее:

{
  not: {
    type: "object",
    required: ["name"]
  }
}

Инверсия нескольких условий

Через anyOf

const schema = {
  not: {
    anyOf: [
      {
        type: "string"
      },

      {
        type: "number"
      }
    ]
  }
}

Допустимы любые значения, кроме строк и чисел.


Через allOf

const schema = {
  not: {
    allOf: [
      {
        type: "number"
      },

      {
        minimum: 0
      }
    ]
  }
}

Запрещены положительные числа и ноль.


Двойное отрицание

Иногда встречается двойная инверсия:

{
  not: {
    not: {
      type: "string"
    }
  }
}

Это эквивалентно:

{
  type: "string"
}

Подобные конструкции обычно ухудшают читаемость схемы.


Производительность

not требует выполнения вложенной схемы полностью.

Сложные конструкции:

{
  not: {
    anyOf: [
      ...
    ]
  }
}

или:

{
  not: {
    allOf: [
      ...
    ]
  }
}

могут увеличивать стоимость валидации, особенно при глубокой вложенности и больших объектах.


Когда not особенно полезен

Исключение специальных случаев

{
  not: {
    const: "deprecated"
  }
}

Запрет конфликтующих конфигураций

{
  not: {
    required: ["ssl", "insecureMode"]
  }
}

Исключение небезопасных комбинаций

{
  not: {
    properties: {
      role: {
        const: "guest"
      },
      accessLevel: {
        const: "full"
      }
    },

    required: ["role", "accessLevel"]
  }
}

Сравнение с другими логическими ключевыми словами

Ключевое слово Назначение
allOf Все схемы должны пройти
anyOf Достаточно одной схемы
oneOf Должна пройти только одна
not Схема не должна проходить

Рекомендации по использованию

Добавление type

Почти всегда полезно явно указывать тип:

{
  not: {
    type: "object",
    required: ["token"]
  }
}

Избегание чрезмерной вложенности

Плохо читается:

{
  not: {
    anyOf: [
      {
        allOf: [
          ...
        ]
      }
    ]
  }
}

Явное описание запрета

Хорошая схема легко читается как правило:

not: {
  const: "admin"
}

или:

not: {
  required: ["password"]
}

Краткая схема поведения not

Вложенная схема Результат not
Валидна Ошибка
Невалидна Успех

Типичные сценарии применения

Задача Решение
Запрет значения not + const
Исключение списка not + enum
Запрет типа not + type
Исключение структуры not + properties
Запрет поля not + required
Исключение шаблона not + pattern
Запрет диапазона not + minimum/maximum