Йо! Недавно мне довелось писать метод валидации промежутка дат для yup. Там мне понадобилось получить данные ref начальной даты в методе валидации конечной даты. В методах yup не очевидно как получать данные из ref в схемах не являющихся StringShema.
В этой статье я расскажу как получать данные ref 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 всё предусмотрел (но не в документации).
Дело в том, что в методах .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'), 'Проверка периода дат')) })
Думаю, что не нужно объяснять что в этом случае не подходят стрелочные функции.