76 lines
2.1 KiB
TypeScript
76 lines
2.1 KiB
TypeScript
/**
|
|
* Result<T, E> — a lightweight, framework-agnostic result type used across
|
|
* `@elly/shared`, `@elly/core`, and `@elly/bot`.
|
|
*
|
|
* Prefer this over throwing for expected/recoverable failures crossing
|
|
* module or IPC boundaries. Reserve exceptions for genuinely exceptional
|
|
* conditions (programmer error, invariant violation, infrastructure failure).
|
|
*/
|
|
|
|
export type Ok<T> = { readonly ok: true; readonly value: T };
|
|
export type Err<E> = { readonly ok: false; readonly error: E };
|
|
export type Result<T, E = Error> = Ok<T> | Err<E>;
|
|
|
|
export function ok<T>(value: T): Ok<T> {
|
|
return { ok: true, value };
|
|
}
|
|
|
|
export function err<E>(error: E): Err<E> {
|
|
return { ok: false, error };
|
|
}
|
|
|
|
export function isOk<T, E>(result: Result<T, E>): result is Ok<T> {
|
|
return result.ok;
|
|
}
|
|
|
|
export function isErr<T, E>(result: Result<T, E>): result is Err<E> {
|
|
return !result.ok;
|
|
}
|
|
|
|
/**
|
|
* Unwrap a Result or throw the error. Use sparingly — defeats the purpose of
|
|
* Result in most call sites.
|
|
*/
|
|
export function unwrap<T, E>(result: Result<T, E>): T {
|
|
if (result.ok) return result.value;
|
|
throw result.error instanceof Error
|
|
? result.error
|
|
: new Error(`Result.unwrap on Err: ${String(result.error)}`);
|
|
}
|
|
|
|
/**
|
|
* Map the success value of a Result without affecting the error branch.
|
|
*/
|
|
export function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {
|
|
return result.ok ? ok(fn(result.value)) : result;
|
|
}
|
|
|
|
/**
|
|
* Map the error value of a Result without affecting the success branch.
|
|
*/
|
|
export function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {
|
|
return result.ok ? result : err(fn(result.error));
|
|
}
|
|
|
|
/**
|
|
* Wrap a throwing synchronous function in a Result.
|
|
*/
|
|
export function tryCatch<T>(fn: () => T): Result<T, Error> {
|
|
try {
|
|
return ok(fn());
|
|
} catch (e) {
|
|
return err(e instanceof Error ? e : new Error(String(e)));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrap a throwing async function in a Result.
|
|
*/
|
|
export async function tryCatchAsync<T>(fn: () => Promise<T>): Promise<Result<T, Error>> {
|
|
try {
|
|
return ok(await fn());
|
|
} catch (e) {
|
|
return err(e instanceof Error ? e : new Error(String(e)));
|
|
}
|
|
}
|