【问题标题】:How to validate array length with io-ts?如何使用 io-ts 验证数组长度?
【发布时间】:2019-12-17 04:17:10
【问题描述】:

我正在处理io-ts 验证,我想验证列表长度(它必须在最小值和最大值之间)。我想知道是否有办法实现这种行为,因为它可以在运行时非常方便地用于 API 端点验证。

到目前为止我所拥有的是

interface IMinMaxArray {
  readonly minMaxArray: unique symbol // use `unique symbol` here to ensure uniqueness across modules / packages
}

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

上面的代码不起作用,它需要Array-s 的参数,并且t.array 也不被接受。我怎样才能以通用的方式完成这项工作?

【问题讨论】:

    标签: javascript arrays typescript validation


    【解决方案1】:

    您的定义缺少数组的类型和编解码器。您可以通过对接口定义进行一些修改并使用编解码器扩展品牌类型来完成这项工作:

    interface IMinMaxArray<T> extends Array<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'
    );
    

    现在您可以创建类似的定义

    minMaxArray(3,5, t.number)
    

    如果您希望定义更加通用和可组合,您可以编写一个接受谓词的通用品牌类型:

    interface RestrictedArray<T> extends Array<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>
    }
    

    现在您可以定义您的限制。单独定义 min 和 max 可能是个好主意,因为它们本身也很有用:

    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));
    

    结合这两个你可以定义minMaxArray:

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

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-03
      • 2021-05-31
      • 2019-04-07
      • 2021-01-27
      • 1970-01-01
      • 1970-01-01
      • 2020-12-11
      • 2021-09-18
      相关资源
      最近更新 更多