交叉口类型的 io-ts 解码器错误

Io-ts decoder error for intersection type

目前我正在做一个有 fp-ts 和 io-ts 栈的项目。我正在尝试使用 io-ts 验证我们从后端获得的所有响应。我开始知道 io-ts 没有简单的方法来制作 optional 类型的 typescript。 从这个 issue 找到了一个变通方法来制作带有可选字段的对象。

我想创建看起来像这样的类型。

type finalType = {
  req: string;
  opt?: string;
};

在我们的项目中,我们有这个 runDecoder 函数来验证 io-ts 类型的响应数据。它与非可选的普通 io-ts 类型完美配合。

但是当它试图验证在 t.intersection 类型的帮助下成为可选的类型时,验证就会出现问题。这是带有示例的代码

import * as Either from "fp-ts/lib/Either";
import * as io from "io-ts";

export const runDecoder = <T extends io.Props>(type: io.TypeC<T>) => (
  data: unknown
) => {
  const result = type.decode(data);
  if (Either.isLeft(result)) {
    return Error("error");
  }
  return result.right;
};

// I want to create type something like this
// type finalType = {
//   req: string;
//   opt?: string;
// };

const OptionType = io.partial({
  opt: io.string
});

const RequiredType = io.type({
  req: io.string
});

const FinalType = io.intersection([RequiredType, OptionType]);

type resultType = io.TypeOf<typeof FinalType>;

const respose:resultType = {
  req: "str"
};

const decoded = runDecoder(FinalType)(respose);

我得到的错误是

Argument of type 'IntersectionC<[TypeC<{ req: StringC; }>, PartialC<{ opt: StringC; }>]>' is not assignable to parameter of type 'TypeC<Props>'.
  Property 'props' is missing in type 'IntersectionC<[TypeC<{ req: StringC; }>, PartialC<{ opt: StringC; }>]>' but required in type 'TypeC<Props>'.

我试图理解这个错误,但我无法弄清楚 runDecoder 方法有什么问题。这里是Codesandboxlink。 任何帮助将不胜感激。

问题是 FinalTypeIntersectionType,而 runDecoder 接受 TypeC

Type<A, O, I>
├ InterfaceType<P, A, O, I>     (+ readonly props: P)
│ └ TypeC<P extends Props>
└ IntersectionType<CS, A, O, I> (+ readonly types: CS)

我还没有使用过 io-ts,但对我来说 InterfaceType class(因此也是扩展它的 TypeC 接口)是仅适用于简单对象类型(如 {req: string; opt?: string})的编解码器,不适用于交集类型(如 {req: string} & {opt?: string})。尽管 TypeScript 中的这些类型在语义上可能是等价的,但它们在 io-ts 中的表示方式不同。

您收到的错误是由于 FinalType 没有 InterfaceType 中所需的 props 属性,因为 FinalType 是一个 IntersectionType.

我会让 runDecoder 接受简单的 Type or even a DecoderType 扩展):

// I: input type
// A: output type
export const runDecoder = <I, A>(type: io.Decoder<I, A>) => (
  data: I
): A | Error => {
  // ...
}

CodeSandbox