export type Result = Ok | Err; export type OkType> = R extends Ok ? T : never; export type ErrType> = R extends Err ? E : never; export function ok(t: T) { return new Ok(t); } export function err(e: E) { return new Err(e); } export function unwrap(result: Result): T { if (result.success) return result.data; throw new Error(errorToString(result.error)); } export async function attempt( errMessage: string, callback: () => Promise>, ): Promise>; export async function attempt( errMessage: string, callback: () => Promise, ): Promise>; export async function attempt( errMessage: string, callback: () => Promise>, ): Promise> { try { const value = await callback(); if (value instanceof Ok || value instanceof Err) return value; return ok(value); } catch { return err(errMessage); } } export function toErrString(error: unknown): Err { return err(errorToString(error)); } export function errorToString(error: unknown): string { if (error instanceof Error) return error.message; if (typeof error === "string") return error; if (typeof error === "object" && error !== null) { // Try to extract message from error object const errorObj = error as Record; if ("message" in errorObj && typeof errorObj["message"] === "string") { return errorObj["message"]; } if ("error" in errorObj && typeof errorObj["error"] === "string") { return errorObj["error"]; } if ("reason" in errorObj && typeof errorObj["reason"] === "string") { return errorObj["reason"]; } // Fallback: stringify the object return JSON.stringify(errorObj); } if (typeof error === "number" || typeof error === "boolean") return String(error); // Fallback for null/undefined/everything else return String(error); } type UnwrapPromise = | Ok ? InnerT : T> | Err ? InnerE : E>; interface IResult { map(fn: (t: T) => New): Ok | Err; mapErr(fn: (e: E) => New): Ok | Err; andThen>(fn: (t: T) => R): Ok> | Err>; orElse>(fn: (e: E) => R): Ok> | Err; flatten(): Flattened>; promise(): Promise>; } export type Flattened> = [OkType] extends [never] ? Result> : OkType extends Result ? Flattened> extends Result ? Result | InnerE> : never : Result, ErrType>; export function flatten>(r: R): Flattened { let current: Result = r; while (current instanceof Ok && isResult(current.data)) { current = current.data; } return current as Flattened; } function isResult(value: unknown): value is Result { return value instanceof Ok || value instanceof Err; } export class Ok implements IResult { success: true = true; constructor(readonly data: T) {} map(fn: (t: T) => New) { return new Ok(fn(this.data)); } mapErr(_: (e: any) => New) { return this; } andThen>(fn: (t: T) => R) { return fn(this.data); } orElse>(_: (e: any) => R) { return this; } flatten() { return flatten(this); } async promise() { const resolved = await Promise.resolve(this.data); return new Ok(resolved) as UnwrapPromise; } } export class Err implements IResult { success: false = false; constructor(readonly error: E) {} map(_: (t: any) => New) { return this; } mapErr(fn: (e: E) => New) { return new Err(fn(this.error)); } andThen>(_: (t: any) => R) { return this; } orElse>(fn: (e: E) => R) { return fn(this.error); } flatten() { return flatten(this); } async promise() { const resolved = await Promise.resolve(this.error); return new Err(resolved) as UnwrapPromise; } }