是的,验证对象数组最多包含一个对象,其中 属性 = value

Yup validate array of objects contains at most one object where property = value

我正在使用 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.' )
})

对于每个电子邮件输入,都有一个相应的复选框来指示它是否是首选的联系电子邮件地址。 不需要 将电子邮件地址标记为首选。

我想做的是验证数组包含 至多一个 对象,其中 isPreferredContacttrue。如果数组中有 3 个电子邮件对象,并且所有对象的 isPreferredContact 都是 false,则这是一个有效状态。也就是说:

let values = [
  {address: '1@email.com', isPreferredContact: false},
  {address: '2@email.com', isPreferredContact: false},
  {address: '3@email.com', isPreferredContact: false}
] // OK

let values = [
  {address: '1@email.com', isPreferredContact: true},
  {address: '2@email.com', isPreferredContact: false},
  {address: '3@email.com', isPreferredContact: false}
] // OK

let values = [
  {address: '1@email.com', isPreferredContact: true},
  {address: '2@email.com', isPreferredContact: true},
  {address: '3@email.com', isPreferredContact: false}
] // Invalid

我看到了这个答案

Yup: deep validation in array of objects

表明 compact() 方法可用于验证 至少一个 ,因为如果从数组中删除“虚假”值后,数组为空,那么很容易将架构键视为无效。

不过,我看不到任何东西来验证数组是否包含 至多 一个具有 属性 = 值谓词的对象。

有办法吗?

在 GitHub 中查看 Yup 的问题后,盯着 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
  })
})

显然,谓词是一个函数,它接受数组的一个元素并对其执行测试 returns a boolean.

对于标量值数组,这与 el => el === value 一样简单。对于对象数组,它将是 el => el.property === valueel[property] === value.

希望这对其他对此好奇的人有所帮助。