yupで複合 validation 〜春のeslint-disable-next-lineを添えて〜


TL;DR

「2つののフィールドを切り替え可能で、いずれか一つが必須」みたいなやつをyupでやりたかったけど、地味にハマった。
結論としては

  • test を使う
  • thisが必要なのでarrow functionをあきらめる

実装例

フィールド id / email のどちらかが必須というのをやりたい場合

// イメージが湧く程度の適当なjsx

/*
Props
  loginWithId: boolean        ... IDとメールアドレスのどちらを表示するかを保持するProps
  toggleLoginKey: () => void  ... IDとメールアドレスのどちらを表示するかを切り替える関数
*/

{loginWithId && <p><input type="text" name="id" value="" /></p>}
{loginWithId && <p><input type="text" name="email" value="" /></p>}
<button onClick={toggleLoginKey}>

yup.object().shape({
  id: yup
    .string()
    // eslint-disable-next-line func-names
    .test('email', 'ログインIDを入力してください', function(value) {
      return this.parent.email || value
    }),
  email: yup
    .string()
    .email('メールアドレス形式で入力してください')
    // eslint-disable-next-line func-names
    .test('email', 'メールアドレスを入力してください', function(value) {
      return this.parent.id || value
    }),
})

見えなくなったFiledの値はToggleする関数内でemptyにしておく。