TutorialsCourses

Yup Date Validation with Custom Transform

Introduction

Yup is a great validation library, and is extremely flexible when it comes to make adjustments to how your validation should work. It can handle async validation however we'll only focus on synchronous here.

Dates are generally the most complicated to deal with. There are so many intricacies to deal with when validating. If your date value is being stored as a string then we'll need to add in parsing logic to fix that.

By default yup will pass the value to new Date() however depending on the format of your date string that may or may not work.

Basic Yup

If the way you're storing your date value doesn't work when passing to new Date() then you'll need to setup a custom transform.

When setting up a yup validation it can work on a single value or an object. To validate an object we'd use the object import from yup like so import { object } from "yup";

Our validation schema would then be setup to mirror what the object structure will be to validate.

const schema = object({
  //object keys for validation go here
});

So if we were to do a required name, and email our validation would look something like this. We'd need to import string from yup first.

const schema = object({
  name: string().required(),
  email: string().email().required(),
});

Built Ins

Additionally there are many built ins supplied by yup for the specific types, and additionally you can add more if necessary. Thankfully for dates Yup provides a min and max. However as mentioned before depending your date is being stored to validate then you may need to transform the date first before.

Transforms

The transform function will receive both the value and the originalValue. The value in the case of dates would be what was returned from the value after being passed to new Date. The originalValue will be what was passed to new Date. So if it were a string before then our value would be a Date and the originalValue would be a string.

date().transform((value, originalValue) => {});

This matters since any date being passed in could be a string, or date and you need to decide how each should be treated. There are some helpers that yup provides however for date work I decided to use date-fns.

We first check if the originalValue (could be string or date) is a date. If it is we use it, otherwise we attempt to parse the date using date-fns parse method.

The parse method will return either a new Date or an Invalid Date. If an Invalid Date is returned then our validation will fail. Otherwise if a proper Date is returned then the other assertions will use the Date value to validate your data.

With parse we specify the format and in this case we would expect a value such as year-month-date, but if your date string value is something else than you'll need to adjust that to match.

import { parse, isDate } from "date-fns";

function parseDateString(value, originalValue) {
  const parsedDate = isDate(originalValue)
    ? originalValue
    : parse(originalValue, "yyyy-MM-dd", new Date());

  return parsedDate;
}

Using Our Transform

The one thing to note when using our transform call is that even the today new Date() is passed into the transform. So this is why it's crucial for our parse function to check if the value is a date already.

import { date, object } from "yup";

const today = new Date();

const schema = object({
  birthday: date().transform(parseDateString).max(today),
});

const isValid = schema.validateSync({
  birthday: "2020-02-02",
});

Then we can call one of Yups validate methods, and it all works flawlessly.