enum tag { 'right' = 'right', 'left' = 'left', } export interface ILeft { value: A; tag: tag.left; } export interface IRight { value: B; tag: tag.right; } export type Either = ILeft | IRight; export type Maybe = Either; export const Left = (val: A): ILeft => ({ value: val, tag: tag.left }); export const Right = (val: B): IRight => ({ value: val, tag: tag.right }); export const isLeft = (val: Either): val is ILeft => (val as ILeft).tag === tag.left; export const isRight = (val: Either): val is IRight => (val as IRight).tag === tag.right; export const either = (leftFn: (left: L) => A, rightFn: (right: R) => B, value: Either): A | B => { if (isLeft(value)) { return leftFn(value.value); } return rightFn(value.value); }; export const whenRight = (resolve: (value: R) => Promise | T) => async (value: Either | Promise>) => { const result = await value; return isRight(result) ? resolve(result.value) : result } export const tryCatch = async (fn: () => Promise): Promise> => { try { return Right(await fn()); } catch (error) { return Left(error); } };