Skip to content Skip to sidebar Skip to footer

How To Validate Array Length With Io-ts?

I am working on an io-ts validation where I would like to validate the list length (it has to be between min and max). I am wondering if there's a way to achieve this behavior sinc

Solution 1:

Your definition is missing the typing and the codec for the array. You could make this work with a few modifications on the interface definition and extending the branded type with a codec:

interface IMinMaxArray<T> extendsArray<T> {
  readonly minMaxArray: unique symbol
}

const minMaxArray = <C extends t.Mixed>(min: number, max: number, a: C) => t.brand(
  t.array(a),
  (n: Array<C>): n is t.Branded<Array<C>, IMinMaxArray<C>> => min < n.length && n.length < max,
  'minMaxArray'
);

Now you can create a definition like

minMaxArray(3,5, t.number)

If you want the definition to be more generic and composable, you could write a generic branded type that accepts a predicate:

interface RestrictedArray<T> extendsArray<T> {
  readonly restrictedArray: unique symbol
}

const restrictedArray = <C>(predicate: Refinement<C[], ArrayOfLength<C>>) => <C extends t.Mixed>(a: C) => t.brand(
  t.array(a), // a codec representing the type to be refined
  (n): n is t.Branded<C[], RestrictedArray<C>> => predicate(n), // a custom type guard using the build-in helper `Branded`'restrictedArray'// the name must match the readonly field in the brand
)

interface IRestrictedArrayPredicate<C extends t.Mixed> {
  (array: C[]): array is ArrayOfLength<C>
}

Now you can define your restrictions. It's probably a good idea to define min and max separately, since they can be useful on their own too:

const minArray = <C extends t.Mixed>(min: number) 
  =>restrictedArray(<IRestrictedArrayPredicate<C>>((array) => array.length >= min));
const maxArray = <C extends t.Mixed>(max: number)
  =>restrictedArray(<IRestrictedArrayPredicate<C>>((array) => array.length <= max));

And combining these two you can define minMaxArray:

exportconst minMaxArray = <C extends t.Mixed>(min: number, max: number, a: C) => t.intersection([minArray(min)(a), maxArray(max)(a)])

Hope this helps.

Post a Comment for "How To Validate Array Length With Io-ts?"