|
| 1 | +import { IMaybe } from '../interfaces' |
| 2 | +import { maybe } from './maybe' |
| 3 | + |
| 4 | +const returnTrue = () => true |
| 5 | +const returnFalse = () => false |
| 6 | +const returnValue = <T>(val: T) => () => val |
| 7 | +const returnMaybe = <T>(val: T) => () => maybe<T>(val) |
| 8 | +const throwReferenceError = (message: string) => () => { throw new ReferenceError(message) } |
| 9 | + |
| 10 | +type Predicate = () => boolean |
| 11 | + |
| 12 | +export interface IResultMatchPattern<T, E, U> { |
| 13 | + readonly ok: (val: T) => U |
| 14 | + readonly fail: (val: E) => U |
| 15 | +} |
| 16 | + |
| 17 | +export interface IResult<T, E> { |
| 18 | + isOk(): boolean |
| 19 | + isFail(): boolean |
| 20 | + maybeOk(): IMaybe<T> |
| 21 | + maybeFail(): IMaybe<E> |
| 22 | + unwrap(): T | never |
| 23 | + unwrapOr(opt: T): T |
| 24 | + unwrapFail(): E | never |
| 25 | + match<M>(fn: IResultMatchPattern<T, E, M>): M |
| 26 | + map<M>(fn: (val: T) => M): IResult<M, E> |
| 27 | + mapFail<M>(fn: (err: E) => M): IResult<T, M> |
| 28 | + flatMap<M>(fn: (val: T) => IResult<M, E>): IResult<M, E> |
| 29 | +} |
| 30 | + |
| 31 | +export interface IResultOk<T, E = never> extends IResult<T, E> { |
| 32 | + unwrap(): T |
| 33 | + unwrapOr(opt: T): T |
| 34 | + unwrapFail(): never |
| 35 | + match<M>(fn: IResultMatchPattern<T, never, M>): M |
| 36 | + map<M>(fn: (val: T) => M): IResultOk<M, never> |
| 37 | + mapFail<M>(fn: (err: E) => M): IResultOk<T, never> |
| 38 | +} |
| 39 | + |
| 40 | +export interface IResultFail<T, E> extends IResult<T, E> { |
| 41 | + unwrap(): never |
| 42 | + unwrapOr(opt: T): T |
| 43 | + unwrapFail(): E |
| 44 | + match<M>(fn: IResultMatchPattern<never, E, M>): M |
| 45 | + map<M>(fn: (val: T) => M): IResultFail<never, E> |
| 46 | + mapFail<M>(fn: (err: E) => M): IResultFail<never, M> |
| 47 | + flatMap<M>(fn: (val: T) => IResult<M, E>): IResultFail<never, E> |
| 48 | +} |
| 49 | + |
| 50 | +export const ok = <T, E = never>(val: T): IResultOk<T, E> => { |
| 51 | + return { |
| 52 | + isOk: returnTrue, |
| 53 | + isFail: returnFalse, |
| 54 | + maybeOk: returnMaybe(val), |
| 55 | + maybeFail: maybe, |
| 56 | + unwrap: returnValue(val), |
| 57 | + unwrapOr: _ => val, |
| 58 | + unwrapFail: throwReferenceError('Cannot unwrap a success'), |
| 59 | + map: <M>(fn: (val: T) => M) => ok(fn(val)), |
| 60 | + mapFail: <M>(_: (err: E) => M) => ok(val), |
| 61 | + flatMap: <M>(fn: (val: T) => IResult<M, E>) => fn(val), |
| 62 | + match: <M>(fn: IResultMatchPattern<T, E, M>) => fn.ok(val) |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +export const fail = <T, E>(err: E): IResultFail<T, E> => { |
| 67 | + return { |
| 68 | + isOk: returnFalse, |
| 69 | + isFail: returnTrue, |
| 70 | + maybeOk: maybe, |
| 71 | + maybeFail: returnMaybe(err), |
| 72 | + unwrap: throwReferenceError('Cannot unwrap a failure'), |
| 73 | + unwrapOr: opt => opt, |
| 74 | + unwrapFail: returnValue(err), |
| 75 | + map: <M>(_: (val: T) => M) => fail(err), |
| 76 | + mapFail: <M>(fn: (err: E) => M) => fail(fn(err)), |
| 77 | + flatMap: <M>(_: (val: T) => IResult<M, E>) => fail(err), |
| 78 | + match: <M>(fn: IResultMatchPattern<T, E, M>) => fn.fail(err) |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +/** |
| 83 | + * Utility function to quickly create ok/fail pairs. |
| 84 | + */ |
| 85 | +export const result = <T, E>(predicate: Predicate, okValue: T, failValue: E): IResult<T, E> => |
| 86 | + predicate() |
| 87 | + ? ok<T, E>(okValue) |
| 88 | + : fail<T, E>(failValue) |
| 89 | + |
| 90 | +/** |
| 91 | +* Utility function to quickly create ok/fail pairs, curried variant. |
| 92 | +*/ |
| 93 | +export const curriedResult = |
| 94 | + <T, E>(predicate: Predicate) => |
| 95 | + (okValue: T) => |
| 96 | + (failValue: E): IResult<T, E> => |
| 97 | + result(predicate, okValue, failValue) |
0 commit comments