UNPKG

lib-result

Version:

A Rust-inspired `Result` type for type-safe error handling in TypeScript and JavaScript

327 lines (323 loc) 6.82 kB
// src/utils.ts function toError(e) { if (e instanceof Error) return e; if (typeof e === "string") return new Error(e); if (isKeyValue(e)) return createCustomError(e); return new Error("Unknown error"); } function isKeyValue(value) { return typeof value === "object" && value !== null && !Array.isArray(value); } function createCustomError(props) { const error = new Error(props?.message || "Unknown Error"); if (isKeyValue(props)) { return Object.assign(error, props); } return error; } // src/result-methods.ts function createWithAnd({ err }) { return function withAnd(base) { return Object.assign(base, { and(result) { if (this.isOk()) return result; return err(this.error); } }); }; } function createWithAndThen({ err }) { return function withAndThen(base) { return Object.assign(base, { andThen(fn) { try { if (this.isOk()) return fn(this.ok); return err(this.error); } catch (e) { throw toError(e); } } }); }; } function withExpect(base) { return Object.assign(base, { expect(message) { if (this.isOk()) return this.ok; throw createCustomError({ message, cause: this.error }); } }); } function withExpectErr(base) { return Object.assign(base, { expectErr(message) { if (this.isError()) return this.error; throw createCustomError({ message, cause: this.error }); } }); } function withInspect(base) { return Object.assign(base, { inspect(fn) { if (this.isOk()) fn(this.ok); return this; } }); } function withInspectErr(base) { return Object.assign(base, { inspectErr(fn) { if (this.isError()) fn(this.error); return this; } }); } function withIsError(base) { return Object.assign(base, { isError() { return this.error !== void 0; } }); } function withIsOk(base) { return Object.assign(base, { isOk() { return this.error === void 0; } }); } function createWithMap({ err, ok }) { return function withMap(base) { return Object.assign(base, { map(fn) { try { if (this.isOk()) return ok(fn(this.ok)); return err(this.error); } catch (e) { throw toError(e); } } }); }; } function withMapOr(base) { return Object.assign(base, { mapOr(defaultValue, fn) { try { if (this.isError()) return defaultValue; return fn(this.ok); } catch (e) { throw toError(e); } } }); } function withMapOrElse(base) { return Object.assign(base, { mapOrElse(defaultFn, fn) { try { if (this.isError()) return defaultFn(this.error); return fn(this.ok); } catch (e) { throw toError(e); } } }); } function createWithMapErr({ err, ok }) { return function withMapErr(base) { return Object.assign(base, { mapErr(fn) { try { if (this.isOk()) return ok(this.ok); return err(fn(this.error)); } catch (e) { throw toError(e); } } }); }; } function withMatch(base) { return Object.assign(base, { match(matchers) { try { return this.isError() ? matchers.errFn(this.error) : matchers.okFn(this.ok); } catch (e) { throw toError(e); } } }); } function createWithOr({ ok }) { return function withOr(base) { return Object.assign(base, { or(result) { if (this.isOk()) return ok(this.ok); return result; } }); }; } function createWithOrElse({ ok }) { return function withOrElse(base) { return Object.assign(base, { orElse(fn) { try { if (this.isError()) return fn(this.error); return ok(this.ok); } catch (e) { throw toError(e); } } }); }; } function withUnwrap(base) { return Object.assign(base, { unwrap() { if (this.isOk()) return this.ok; throw this.error; } }); } function withUnwrapErr(base) { return Object.assign(base, { unwrapErr() { if (this.isError()) return this.error; throw new Error(`Received an Ok value '${this.ok}' instead of an Error`); } }); } function withUnwrapOr(base) { return Object.assign(base, { unwrapOr(fallback) { return this.isOk() ? this.ok : fallback; } }); } function withUnwrapOrElse(base) { return Object.assign(base, { unwrapOrElse(fn) { try { if (this.isOk()) return this.ok; return fn(this.error); } catch (e) { throw toError(e); } } }); } function createResultMethods({ err, ok }) { return [ createWithAnd({ err }), createWithAndThen({ err }), withExpect, withExpectErr, withInspect, withInspectErr, withIsError, withIsOk, createWithMap({ err, ok }), withMapOr, withMapOrElse, createWithMapErr({ err, ok }), withMatch, createWithOr({ ok }), createWithOrElse({ ok }), withUnwrap, withUnwrapErr, withUnwrapOr, withUnwrapOrElse ]; } // src/mixins.ts function compose(base, ...fns) { return Object.freeze(fns.reduce((obj, fn) => fn(obj), base)); } function Ok(ok) { return compose({ ok, error: void 0 }, ...methodsArray); } function Err(error) { if (!(error instanceof Error)) { throw new TypeError( "Err() expects an Error instance, use ErrFromObject() instead." ); } return compose({ ok: void 0, error }, ...methodsArray); } var methodsArray = createResultMethods({ err: Err, ok: Ok }); function ErrFromUnknown(error) { return compose( { ok: void 0, error: toError(error) }, ...methodsArray ); } function ErrFromText(message) { return compose( { ok: void 0, error: new Error(message) }, ...methodsArray ); } function ErrFromObject(props) { return compose( { ok: void 0, error: createCustomError(props) }, ...methodsArray ); } // src/main.ts function wrap(callback) { try { return Ok(callback()); } catch (error) { return ErrFromUnknown(error); } } async function wrapAsync(callback) { try { return Ok(await callback()); } catch (error) { return ErrFromUnknown(error); } } function wrapThrowable(callback) { return (...args) => { try { return Ok(callback(...args)); } catch (error) { return ErrFromUnknown(error); } }; } function wrapAsyncThrowable(callback) { return async (...args) => { try { return Ok(await callback(...args)); } catch (error) { return ErrFromUnknown(error); } }; } export { Err, ErrFromObject, ErrFromText, ErrFromUnknown, Ok, wrap, wrapAsync, wrapAsyncThrowable, wrapThrowable };