Как получить значение Yup ref или написание собственных методов

Йо! Недавно мне довелось писать метод валидации промежутка дат для yup. Там мне понадобилось получить данные ref начальной даты в методе валидации конечной даты. В методах yup не очевидно как получать данные из ref в схемах не являющихся StringShema.

В этой статье я расскажу как получать данные ref yup’а независимо от типа схем.

Как создаются методы в yup

Сначала давайте вспомним как в yup создаются методы. Я уже частично рассматривал это в одной из статей, но в этот раз сделаю это подробнее.

Мы создаём функцию, принимающую некоторые параметры, из которой возвращаем изменённый каким-то образом this.

В JS это выглядит так:

function checkPayment(ref, msg) {
  return this.test({
    name: 'checkPaymentMethod',
    exclusive: false,
    message: msg || 'accountNumber not valid', // Сообщение об ошибке
    params: { reference: ref ? ref.path : undefined },
    test: function (value) {
      return checkPaymetAccount(value, this.resolve(ref)) // Функция валидации
    }
  })
}
yup.addMethod(yup.string, 'checkPaymentMethod', checkPayment)

В TypeScript так:

function checkPayment(this: yup.StringSchema, ref: yup.Ref, msg?: string ) {
  return this.test({
    name: 'checkPaymentMethod',
    exclusive: false,
    message: msg || 'accountNumber not valid', // Сообщение об ошибке
    params: { reference: ref ? ref.path : undefined },
    test: function (value?: string) {
      return checkPaymetAccount(value, this.resolve(ref)) // Функция валидации
    }
  })
}
yup.addMethod<yup.StringSchema>(yup.string, 'checkPaymentMethod', checkPayment)

Если вы добавляете метод к yup.string, то в this функции есть метод this.resolve, который принимает ref и возвращает его значение и выглядит это так:

function checkPayment(ref, msg) {
  const refValue = this.resolve(ref)
.......
}

так это выглядит в JS, а так в TS:

function checkPayment(this: yup.StringSchema, ref: yup.Ref, msg?: string ) {
  const refValue = this.resolve(ref)
.......
}

Но если вы добавляете метод не к yup.string (yup.StringShema), то данный метод отсутствует. Что делать?! Yup всё предусмотрел (но не в документации).

Получаем данные ref

Дело в том, что в методах .test() yup’а существует собственный контекст (yup.TestContext), в котором всегда есть метод resolve, получающий данные из ref.

В JS

function magicDate(ref, msg) {
 const that = this
  return that.test({
    name: 'magicDate',
    exclusive: false,
    message: msg || 'magicDate not valid', // Сообщение об ошибке
    params: { reference: ref ? ref.path : undefined },
    test: function (value) {
      const refValue = this.resolve(ref)
      return // Ваша магия
    }
  })
}
yup.addMethod(yup.date, 'magicDate', magicDate)

В typescript:

function magicDate(this: yup.DateSchema, ref: yup.Ref, msg?: string) {
  return this.test({
    name: 'magicDate',
    exclusive: false,
    message: msg || 'magicDatenot valid', // Сообщение об ошибке
    params: { reference: ref ? ref.path : undefined },
    test: function (this, value) {
      const refValue = this.resolve(ref)
      return // Ваша магия
    }
  })
}
yup.addMethod(yup.date, 'magicDate', magicDate)

Не зависимо от типа схемы в контексте метода test будет метод resolve. А так же нет разницы к какому типу схемы относиться поле из ref.

Пример

function magicDate(ref, msg) {
  let startDate
  return this.test({
    name: 'magicDate',
    exclusive: false,   
    params: { reference: ref ? ref.path : undefined },
    test: function (value) {
      const startDate= this.resolve(ref)
      return // Ваша магия
    },
    message: function(params){
        const { value } = params
        return msg || `Начальная дата: ${ startDate }, конечная дата: ${value} `
    }
  })
}
yup.addMethod(yup.date, 'magicDate', magicDate)

const validateSchema = yup.object().shape({
    startDate: yup.date().requiere(),
    endDate: yup.date().magicDate(yup.ref('startDate'), 'Проверка периода дат'))
})

Думаю, что не нужно объяснять что в этом случае не подходят стрелочные функции.