pragmatic-fp-ts
Version:
Opinionated functional programming library with easy use in mind
73 lines (69 loc) • 2.67 kB
text/typescript
import { Effect, Mappable, UnboxPromise } from "./types.ts";
export interface ErrorLog<T> {
_: <U>(f: Mappable<T, U>) => ErrorLog<U>;
effect: (f: Effect<T>) => ErrorLog<T>;
try: <U>(f: Mappable<T, U>, alt: U) => ErrorLog<U>;
getErrors: () => Error[];
getValue: () => T;
getValueOr: <U>(alt: U) => NonNullable<T> | U;
hasErrors: () => boolean;
}
function ErrorLog<T>(expr: T, errors: Array<Error> = []) {
return {
_: <U>(f: Mappable<T, U>) => ErrorLog(f(expr), errors),
try: <U>(f: Mappable<T, U>, alt: U): ErrorLog<U> => {
try {
return ErrorLog(f(expr), errors);
} catch (err) {
return ErrorLog(alt, [...errors, err as Error]);
}
},
effect: (f: Effect<T>): ErrorLog<T> => {
try {
f(expr);
return ErrorLog(expr, errors);
} catch (err) {
return ErrorLog(expr, [...errors, err as Error]);
}
},
getErrors: () => errors,
getValue: () => expr,
getValueOr: <U>(alt: T | U) => (expr || alt) as NonNullable<T> | U,
hasErrors: () => errors.length > 0,
};
}
export interface FutureErrorLog<T> {
_: <U>(f: Mappable<T, U>) => FutureErrorLog<U>;
effect: (f: Effect<T>) => FutureErrorLog<T>;
try: <U>(f: Mappable<T, U>, alt: UnboxPromise<U>) => FutureErrorLog<U>;
getErrors: () => Promise<Error[]>;
getValue: () => Promise<UnboxPromise<T>>;
getValueOr: <U extends T>(alt: U) => Promise<NonNullable<UnboxPromise<T>>>;
hasErrors: () => Promise<boolean>;
}
const FutureErrorLog = <T>(
expr: T | Promise<T>,
errors: Promise<Error[]> = Promise.resolve([])
): FutureErrorLog<T> => {
const exprP = expr instanceof Promise ? expr : Promise.resolve(expr);
const tryOrAppendError = (p: Promise<any>, es: Promise<Error[]>) =>
p.then(() => es).catch(async (err) => [...(await errors), err]);
return {
_: <U>(f: Mappable<T, U>): FutureErrorLog<U> => FutureErrorLog(exprP.then(f), errors),
effect: (fx: Effect<T>) => FutureErrorLog(exprP, tryOrAppendError(exprP.then(fx), errors)),
try: <U>(f: Mappable<T, U>, alt: UnboxPromise<U>): FutureErrorLog<U> => {
const p = exprP.then(f);
return FutureErrorLog(
p.catch(() => alt as any),
tryOrAppendError(p, errors)
);
},
getErrors: () => errors,
getValue: () => exprP as unknown as Promise<UnboxPromise<T>>,
getValueOr: async (alt: T | Promise<T>) =>
(await exprP) || ((alt instanceof Promise ? await alt : (alt as any)) as any),
hasErrors: () => errors.then((e) => e.length > 0),
};
};
export const errorLogged = <T>(value: T) => ErrorLog(value);
export const errorLoggedFuture = <T>(value: T) => FutureErrorLog(value);