Skip to content
This repository has been archived by the owner on Feb 16, 2021. It is now read-only.

Dependent validations for structs #29

Closed
mohanzhang opened this issue Sep 17, 2015 · 3 comments
Closed

Dependent validations for structs #29

mohanzhang opened this issue Sep 17, 2015 · 3 comments

Comments

@mohanzhang
Copy link

Is it possible to validate one field of a struct depending on the value of another? In particular, I have a startDate and an optional endDate field, and I would like to make sure that endDate is after startDate, if endDate is given.

More specifically, if I do something like

var MyType = t.struct({
  startDate: t.Dat,
  endDate: t.maybe(t.Dat),
  foo: t.Num
});

How can I validate MyType as a whole? It doesn't seem like struct takes a validator function as an argument?

@gcanti
Copy link
Owner

gcanti commented Sep 17, 2015

Is it possible to validate one field of a struct depending on the value of another

Yes, with a subtype:

function isValid(x) {
  if (t.Dat.is(x.endDate)) {
    return x.endDate.getTime() >= x.startDate.getTime();
  }
  return true;
}

var MyType = t.subtype(t.struct({
  startDate: t.Dat,
  endDate: t.maybe(t.Dat),
  foo: t.Num
}), isValid);

console.log(t.validate({startDate: new Date(2015, 10, 30), foo: 1}, MyType).isValid()); // true
console.log(t.validate({startDate: new Date(2015, 10, 20), endDate: new Date(2015, 10, 21), foo: 1}, MyType).isValid()); // true
console.log(t.validate({startDate: new Date(2015, 10, 20), endDate: new Date(2015, 10, 19), foo: 1}, MyType).isValid()); // false

All the the combinators struct, subtype, list, etc... can be composed at your will

@mohanzhang
Copy link
Author

Ah, that's brilliant! My next question was going to be how to ensure that the validations get layered so that the original struct's validations also run, but with subtype composition, it happens naturally. Thanks 👍!

@chirag04
Copy link

chirag04 commented Apr 15, 2017

@gcanti instead, i feel like the predicate should have access to the options/context.

eg:

isValidConfirmPassword = (confirmPassword, context) => context.password === confirmPassword;

const ConfirmPassword = t.refinement(t.String, isValidConfirmPassword);

const Person = t.struct({
  name: t.String,
  password: t.String,
  confirmPassword: ConfirmPassword,
}, 'Person');


const formValues = { name: 'a', password: 'b', confirmPassword: 'c' };

validate(formValues, Person, { context: formValues });

Or the predicate could have the same signature as validate. (x, type, path, options)

Person struct can be complex and having to set Person as a refinement on struct and then handle all dependent field in one predicate is not ideal imo. makes sense?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants