Да, проверить массив объектов содержит не более одного объекта, где свойство = значение

Я использую Formik FieldArray для динамического добавления объектов в массив, визуализируя дополнительные элементы формы, поскольку объекты push() привязаны к массиву.

Моя схема выглядит так:

const EMAIL_SCHEMA = Yup.object().shape({
  address: Yup.string().email().required( 'E-mail address is required.' ),
  isPreferredContact: Yup.boolean()
})

const SCHEMA = Yup.object().shape({
  emails: Yup.array()
             .of( EMAIL_SCHEMA )
             .ensure()
             .compact( v => !v.address )
             .required( 'At least one e-mail address is required.' )
})

Для каждого ввода электронной почты есть соответствующий флажок, чтобы указать, является ли это предпочтительным контактным адресом электронной почты. Адреса электронной почты не являются обязательными для пометки как предпочтительные.

Я хотел бы убедиться, что массив содержит не более одного объекта, где isPreferredContact равно true. Если в массиве 3 объекта электронной почты и isPreferredContact равно false для всех, это допустимое состояние. То есть:

let values = [
  {address: '[email protected]', isPreferredContact: false},
  {address: '[email protected]', isPreferredContact: false},
  {address: '[email protected]', isPreferredContact: false}
] // OK

let values = [
  {address: '[email protected]', isPreferredContact: true},
  {address: '[email protected]', isPreferredContact: false},
  {address: '[email protected]', isPreferredContact: false}
] // OK

let values = [
  {address: '[email protected]', isPreferredContact: true},
  {address: '[email protected]', isPreferredContact: true},
  {address: '[email protected]', isPreferredContact: false}
] // Invalid

Я вижу этот ответ

Ага: глубокая проверка в массиве объектов

показывает, что метод compact() может использоваться для проверки по крайней мере одного, потому что, если после удаления ложных значений из массива массив пуст, то легко считать ключ схемы недействительным.

Однако я ничего не вижу для проверки того, что массив содержит не более одного объекта с предикатом свойство = значение.

Есть ли способ сделать это?


person diekunstderfuge    schedule 24.06.2020    source источник


Ответы (1)


После изучения проблем Yup в GitHub, просмотра документации API (документ для addMethod действительно ужасен) и тестирования в Code Sandbox, я обнаружил, что это работает:

Yup.addMethod(Yup.array, 'atMostOne', function(args) {
  const { message, predicate } = args
  return this.test('atMostOne', message, function(list) {
    // If there are 2+ elements after filtering, we know atMostOne must be false.
    return list.filter(predicate).length < 2
  })
})

Предикат, очевидно, представляет собой функцию, которая принимает элемент массива и выполняет на нем тест, который возвращает boolean.

Для массива скалярных значений это так же просто, как el => el === value. Для массива объектов это будет el => el.property === value или el[property] === value.

Надеюсь, это поможет кому-нибудь еще, кому это интересно.

person diekunstderfuge    schedule 25.06.2020