Ошибка декодера ввода-вывода для типа пересечения

#javascript #typescript #fp-ts

Вопрос:

В настоящее время я работаю над проектом, в котором есть стек fp-ts и io-ts. Я пытаюсь проверить все ответы, которые мы получаем от бэкенда io-ts . Я узнал io-ts , что нет простого способа сделать optional тип typescript . И из этой проблемы я нашел обходной путь, чтобы сделать объект с необязательными полями.

Я хочу создать тип, который выглядит примерно так.

 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 методом. Вот ссылка на Codesandbox.
Любая помощь будет очень признательна.

Ответ №1:

Проблема в том , что FinalType это a IntersectionType , тогда runDecoder как принимает a 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 , что класс (и, следовательно TypeC , интерфейс, который его расширяет) предназначен только для кодеков для простого типа объектов (например {req: string; opt?: string} ), а не для типов пересечений (например {req: string} amp; {opt?: string} ). Даже несмотря на то, что эти типы в TypeScript могут быть семантически эквивалентны, они не представлены одинаково в io-ts.

Ошибка, которую вы получаете, связана с FinalType отсутствием props свойства, требуемого в InterfaceType because FinalType is an IntersectionType .

Я бы сделал runDecoder так, чтобы принять просто a Type или даже a Decoder (что Type распространяется):

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

CodeSandbox

Комментарии:

1. большое вам спасибо за объяснение ошибки и решение. Теперь это имеет для меня смысл!