tiinvo
Version:
A library of types and utilities for your TypeScript and JavaScript projects
250 lines (249 loc) • 5.62 kB
JavaScript
import { make as makecatch } from './Catch.js';
import { catchableAsync, catchableSync } from './Functors.js';
/**
* Returns an `Err`
*
* @example
*
* ```ts
* import { Result } from 'tiinvo';
*
* Result.err(10) instanceof Error // true
* Result.err(new TypeError('aaaa')) instanceof Error // true
* Result.err({}) instanceof Error // true
* Result.err(10n) instanceof Error // true
* Result.err([10, 20, 30]) instanceof Error // true
* ```
*
* @param a
* @returns
* @group Factories
* @since 3.8.0
*/
export const err = (a) => {
if (a instanceof Error) {
return a;
}
else if (typeof a === 'object' && a) {
const err = new Error();
for (const [key, value] of Object.entries(a)) {
err[key] = value;
}
return err;
}
return new Error(String(a));
};
//#region guards
/**
* Checks if a value is `Err`
*
* @example
*
* ```ts
* import { Result } from 'tiinvo';
*
* Result.isErr(10) // false
* Result.isErr(new TypeError('aaaa')) // true
* ```
*
* @param x the value to check
* @returns true if `x` is `Err`, false otherwise
* @group Guardables
* @since 4.0.0
*/
export const isErr = (x) => x instanceof Error || (typeof x === 'object' && x !== null && 'message' in x && 'name' in x && 'cause' in x);
/**
* Checks if a value is `Ok`
*
* @example
*
* ```ts
* import { Result } from 'tiinvo';
*
* Result.isOk(10) // true
* Result.isOk(new TypeError('aaaa')) // false
* ```
*
* @param x
* @returns true if `x` is `Ok<A>`, false otherwise
* @group Guardables
* @since 4.0.0
*/
export const isOk = (x) => !isErr(x);
/**
* Checks if a value is `Ok<A>`
*
* ```ts
* import { Num, Result } from 'tiinvo';
*
* const guard = Result.isOkOf(Num.guard);
*
* guard(10) // true
* guard("hello") // false
* guard(new TypeError('aaaa')) // false
* ```
*
* @template A the type
* @param g the type guard
* @returns the Guard
* @group Guardables
* @since 4.0.0
*/
export const isOkOf = (g) => (x) => isErr(x) ? false : g(x);
export function cmp(cmp, a, b) {
const _cmp = (x, y) => {
if (isErr(x) && isErr(y)) {
return 0;
}
if (isErr(x)) {
return -1;
}
if (isErr(y)) {
return 1;
}
return typeof cmp === 'function' ? cmp(x, y) : cmp.cmp(x, y);
};
switch (arguments.length) {
case 3: return _cmp(a, b);
case 2: return (b) => _cmp(b, a);
case 1: return (a, b) => _cmp(a, b);
}
}
;
export function eq(eq, a, b) {
const _eq = (x, y) => {
if (isErr(x) && isErr(y)) {
return true;
}
if (isErr(x) || isErr(y)) {
return false;
}
return typeof eq === 'function' ? eq(x, y) : eq.eq(x, y);
};
switch (arguments.length) {
case 3: return _eq(a, b);
case 2: return (b) => _eq(a, b);
case 1: return (a, b) => _eq(a, b);
}
}
;
export function filter(f, a) {
const _err = Error("Value did not pass filter");
if (arguments.length === 2) {
return isErr(a) ? _err : f(a) ? a : _err;
}
return (c) => isErr(c) ? _err : f(c) ? c : _err;
}
//#endregion
//#region mappables
/**
* Maps `Result.t<a>` to `Result.t<b>` if ok, otherwise returns `err`
*
* ```ts
* import { Num, Result } from 'tiinvo';
*
* const m = Result.map(Num.add(10))
*
* m(10) // 20
* m(new Error('foobar!')) // Error('foobar!')
* ```
*
* @param m the Mappable functor
* @returns
* @since 4.0.0
*/
export const map = (m) => (a) => isOk(a) ? m(a) : a;
/**
* Maps `Result.t<a>` to `Result.t<b>` if ok, otherwise returns `b`
*
* ```ts
* import { Str, Result } from 'tiinvo';
*
* const map = Result.mapOr(Str.length, 0);
*
* map('hello') // 5
* map(new Error()) // 0
* ```
*
* @param value
* @returns
* @since 4.0.0
*/
export const mapOr = (m, b) => (a) => isOk(a) ? m(a) : b;
//#endregion
//#region catchables
/**
* Calls a function `f` with it's arguments and returns a `Promise<Result.t<ReturnType<f>>>`
*
* ```typescript
* import { Result, Num } from 'tiinvo';
*
* const fn = async (arg: number) => {
* if (Num.isEven(arg)) {
* return arg * 2;
* }
*
* throw new Error(`${arg} is not even`);
* }
*
* const safe = Result.tryAsync(fn);
*
* await safe(2) // 4
* await safe(3) // Error("3 is not even")
*
* Result.isOk(await safe(2)) // true
* Result.isErr(await safe(3)) // true
* ```
*
* @param fn
* @returns
* @since 4.0.0
*/
export const tryAsync = (f) => {
return makecatch({
[catchableAsync]() {
return {
catch: async (error) => error,
func: f
};
}
});
};
/**
* Calls a function `f` with it's arguments and returns a `Promise<Result.t<ReturnType<f>>>`
*
* ```typescript
* import { Result, Num } from 'tiinvo';
*
* const fn = (arg: number) => {
* if (Num.isEven(arg)) {
* return arg * 2;
* }
*
* throw new Error(`${arg} is not even`);
* }
*
* const safe = Result.trySync(fn);
*
* safe(2) // 4
* safe(3) // Error("3 is not even")
*
* Result.isOk(safe(2)) // true
* Result.isErr(safe(3)) // true
* ```
*
* @param fn
* @returns
* @since 4.0.0
*/
export const trySync = (f) => {
return makecatch({
[catchableSync]() {
return {
catch: (error) => error,
func: f
};
}
});
};
//#endregion