import { DefaultOrFunc, getDefault } from "./fn" import { None, Maybe, Voidable, isNone } from "./maybe" import { UnionToIntersection } from "./types" /** Means success */ export interface Ok { res: T } /** Means failure */ export interface Err { err: E } /** Union of success or failure * ```ts * type Result = Ok | Err * ``` */ export type Result = Ok | Err /** Make a `Ok` */ export function ok(res: T): Ok { return { res } } /** Make a `Err` */ export function err(err: E): Err { return { err } } /** Check value is `OK` */ export function isOk(v?: any): v is Ok { return typeof v === 'object' && v !== null && 'res' in v } /** Check value is `Err` */ export function isErr(v?: any): v is Err { return typeof v === 'object' && v !== null && 'err' in v } /** Check value is `Result` */ export function isResult(v?: any): v is Result { return typeof v === 'object' && v !== null && ('res' in v || 'err' in v) } /** Get `T` in `Ok` */ export function getOk(v: Ok): T /** Get nothing */ export function getOk(v: Err): undefined /** Get `T` in `Result` */ export function getOk(v: Result): Voidable /** Get nothing */ export function getOk(v?: undefined): undefined /** Get nothing */ export function getOk(v?: null): null /** Get nothing */ export function getOk(v?: None): None /** Get `T` in `Result` */ export function getOk(v?: Maybe>): Voidable export function getOk(v?: Maybe>): Voidable { return (v as any).res } /** Get `E` in `Err` */ export function getErr(v: Err): E /** Get nothing */ export function getErr(v: Ok): undefined /** Get `E` in `Result` */ export function getErr(v: Result): Voidable /** Get nothing */ export function getErr(v?: undefined): undefined /** Get nothing */ export function getErr(v?: null): null /** Get nothing */ export function getErr(v?: None): None /** Get `E` in `Result` */ export function getErr(v?: Maybe>): Voidable export function getErr(v?: Maybe>): Voidable { return (v as any).err } export function mapOk(v: Result, f: (val: T) => U): Result { if (isOk(v)) { return ok(f(getOk(v))) } else return v } export function mapErr(v: Result, f: (val: E) => U): Result { if (isErr(v)) { return err(f(getErr(v))) } else return v } export namespace Result { export function and(v: Result, o: DefaultOrFunc>): Result { if (isErr(v)) return v return getDefault(o) } export function or(v: Result, o: DefaultOrFunc>): Result { if (isErr(v)) return getDefault(o) return v } /** Transpose Result to Maybe */ export function transpose(v: Result, E>): Voidable> { if (isOk(v)) { if (isNone(getOk(v))) return return v as Result } return v } type NestedOk = Ok | Ok> type NestedResult = Result | Ok> type FlattenResult = N extends NestedOk ? FlattenResult : N extends Err ? N : Ok /** Flatten result * * ## Example * ```ts * let a: Result<1, 2> = flatten, 2>, 2>>(ok(ok(ok(1)))) * let b: Ok<1> = flatten>>>(ok(ok(ok(1)))) * let c: Err<2> = flatten>>>(ok(ok(err(2)))) * ``` */ export function flatten>(v: N): FlattenResult { while (isOk(v)) { if (isResult(v.res)) { v = v.res as any } else { return v as any } } return v as any } }