Как сузить общий тип с помощью переданной функции защиты?

Давайте рассмотрим Opt из пакета ts-opt (это просто вариант «Может быть / Вариант / Необязательно») и isNumber иметь охранник типа ((x): x is number => ...).

Можно ли реализовать (и как) метод someIf универсальным способом (работая с защитой произвольного типа, типобезопасный, без необходимости указывать пользователю тип, который уже находится в защите типа):

type A = number | string;
const x: A = 4;
const y: A = 'y';
opt(x)               // Opt<number | string>
  .someIf(isNumber); // Opt<number> (Some(4))
opt(y)               // Opt<number | string>
  .someIf(isNumber); // Opt<number> (None)

person menfon    schedule 22.04.2020    source источник


Ответы (1)


Один из способов достижения этого (без использования someIf в качестве функции-прототипа) заключается в следующем

type A = number | string;

const x: A = 4;
const y: A = "y";

const isNumber = (a: any): a is number => typeof a === "number";

const someIf = <T>(ot: Opt<any>, f: (x: any) => x is T): Opt<T> =>
  ot.caseOf(
    t => (f(t) ? opt(t) : none),
    () => none
  );

const ox = someIf(
  opt(x),
  isNumber
); // Opt<number> <- Some(4)

const oy = someIf(
  opt(y),
  isNumber
); // Opt<number> <- None

Ссылка на песочницу


Идея довольно проста. Переверните необязательное значение, если none, нам нечего делать. В противном случае проверьте обернутое значение на соответствие типу защиты. Если защита завершилась успешно, просто верните значение (с суженным типом), иначе верните none.

person bugs    schedule 22.04.2020