首页 > 解决方案 > 没有使用 io-ts 进行未定义验证的数组

问题描述

我们正在使用io-ts来验证来自 HTTP 服务的外部数据。我编写了一个编解码器,它采用另一个编解码器C并返回Either<t.Errors, C | undefined>但实际上从未失败(只是为了满足t.Type)。这是因为从服务中我们得到了不同类型的数组,并且将来可以添加新的类型,因此我们希望它继续工作,但忽略那些未定义的。好像:

export function tryDecode<C extends io.Mixed>(
  codec: C,
  onLeft?: (validation: io.Validation<unknown>) => void,
) {
  return new io.Type<io.TypeOf<C> | undefined, io.OutputOf<C>, unknown>(
    'tryDecode',
    (input: unknown): input is C | undefined => {
      return codec.is(input) || input === undefined;
    },
    (u, c) => {
      const validation = codec.validate(u, c);

      return fold(
        () => {
          if (onLeft) {
            onLeft(validation);
          }

          return io.success(undefined as C | undefined);
        },
        (right: C | undefined) => io.success(right),
      )(validation);
    },
    io.identity,
  );
}

我正在尝试编写一个arrayWithoutUndefined类似io.array但删除任何未定义元素的编解码器。它不应该失败(除非它不是一个数组)。到目前为止我的尝试:

export function arrayWithoutUndefined<C extends io.Mixed>(
  codec: C,
  name = `arrayWithoutUndefined<${codec.name}>`,
) {
  const arr = io.array(codec);

  return new io.Type(
    name,
    (u): u is Array<io.TypeOf<C>> => arr.is(u) && !u.includes(undefined),
    (u, c) =>
      either.chain(codec.validate(u, c), as =>
        io.success(as.filter(notUndefined)),
      ),
    arr.encode,
  );
}

notUndefined确保(a: A | undefined): a is A => .... 然后我会将它们一起使用,const Modules = arrayWithoutUndefined(tryDecode(UnionOfDifferentModules))但 Modules 仍然表示为Array<UnionOfDifferentModules | undefined>当我希望它只是Array<UnionOfDifferentModules>. 这可以用 TypeScript/io-ts 以某种方式表达吗?我研究了条件类型,但不幸的是不知道如何表达。

标签: typescriptvalidation

解决方案


在支持数组过滤语句中的类型保护的较新版本的打字稿中,这个问题可能已经解决了。

的显式泛型也可能在t.Type这里有所帮助。

type Subtract<A, B> = A extends B ? never : A;

return io.Type<Subtract<t.TypeOf<C>, undefined>, unknown[], unknown>(...);

推荐阅读