ianstormtaylor / superstruct

A simple and composable way to validate data in JavaScript (and TypeScript).
https://docs.superstructjs.org
MIT License
6.97k stars 224 forks source link

Validate min is less than max #1029

Closed realworld666 closed 2 years ago

realworld666 commented 2 years ago

If I have a type such as this

export interface MyType{
  title: string;
  minVersion: number;
  maxVersion: number;
}

and a validator

export const myTypeConstraints: Describe<MyType> = object({
  title: size(string(), 2, 100),
  minVersion: number(),
  maxVersion: number()
});

Is there a way I can verify that minVersion is less than maxVersion

andorfermichael commented 2 years ago

I would like to know that too.

arturmuller commented 2 years ago

Hey @realworld666, @andorfermichael — if you're still curious — for something like this, you want to use refinements.

About refinements from the docs:

Superstruct allows you to constrain existing structs with further validation. This doesn't change the type of the struct, but simply introduces extra validation logic.

https://docs.superstructjs.org/api-reference/refinements

In your case, the implementation would look something like this:

type MyType = {
  title: string;
  minVersion: number;
  maxVersion: number;
};

const myTypeConstraints: Describe<MyType> = refine(
  object({
    title: size(string(), 2, 100),
    minVersion: number(),
    maxVersion: number(),
  }),
  "MyType",
  (value) => value.minVersion < value.maxVersion,
);

// This will throw an error
assert(
  { title: "Some title", minVersion: 4, maxVersion: 2 },
  myTypeConstraints,
);

One thing to note is that the error that will be thrown in this case is a bit cryptic (StructError: Expected a value of type "object", but received: "[object Object]"). You can fix that by returning a string from the refiner function, which is used instead of the default message if provided.

It could look something like this:

const myTypeConstraints: Describe<MyType> = refine(
  object({ ... }),
  "MyType",
  (value) => {
    if (value.minVersion < value.maxVersion) {
      return true;
    }

    return (
      "Expected `minVersion` to be greater than `maxVersion` on type `MyType`, but received " +
      JSON.stringify(value)
    );
  },
);
andorfermichael commented 2 years ago

@arturmuller thanks for your effort