Well tested TypeScript functions suitable for use in browser, service worker, and Node.js contexts.
npm i @resolute/std
import { fetchOk } from '@resolute/std/http';
try {
await fetchOk('https://httpstat.us/500');
} catch (error) {
// `fetch` doesn’t throw on 500 responses.
// `fetchOk` does :)
}
Type validation and sanitization. This module contains a handful of utility functions and
“coercers.” Coercers are unary functions that return validated/mutated input, or throw
. The
utility function to
(alias coerce
) allow you to chain these coercers. The or
utility function
may be used in the chain in order to specify a backup value to be returned instead of throwing an
error.
Additionally, the is
and not
utility functions return true
if a coercer or chain of coercers
(to(…)
) passes or false
if it throws.
Chain unary coercing functions.
import { nonempty, or, string, to, trim } from '@resolute/std/coerce';
to(string, trim, nonempty)(' foo '); // 'foo'
to(string, trim, nonempty)(' '); // throws TypeError
to(string, trim, nonempty, or(undefined))(' '); // undefined
Provide a backup value to be used when a coercer fails. If instanceof Error
, then that error will
be throw
n. For any other value, it will be returned. The or(…)
utility function must be the last
parameter in to
.
import { or, string, to } from '@resolute/std/coerce';
to(string, or(null))('foo'); // 'foo'
to(string, or(null))(1); // null
to(string, or(new Error('foo')))(1); // throws Error: foo
Type guard test. Use with any type guard or mutating function that throw
s on failure (almost all
functions here do). The is
function will catch the error and return false
, otherwise it will
return true
.
import { is, string } from '@resolute/std/coerce';
is(string)('foo'); // true
is(string)(12345); // false
Negate type guard test. Use with any type guard or mutating function that throw
s on failure
(almost all functions here do). The not
function will catch the error and return true
, otherwise
it will return false
. @example
import { not, string } from '@resolute/std/coerce';
not(string)('foo'); // false
not(string)(12345); // true
Returns the input if it is a string. Throws otherwise.
Returns the input if it is a finite number. Throws otherwise including when input is NaN
or
Infinity
.
Convert between hex, RGB array, and integer representations of colors. Additionally blend between colors.
Convert a hex color string #xxxxxx or rgb array [r, g, b] to an integer.
import { parse } from '@resolute/std/color';
parse('#888'); // 8947848
#XXXXXX → integer
[r, g, b] → integer
integer → #XXXXXX
integer → [r, g, b]
Blend two colors using a percent.
import { blend, toHex } from '@resolute/std/color';
const blender = blend('#000', '#888');
toHex(blender(0.0)); // #000000 (0%)
toHex(blender(0.5)); // #444444 (50%)
toHex(blender(1.0)); // #888888 (100%)
Runtime and control flow helpers.
Wrap an async or promise-returning function that when called will retry up to retries
times or
until it resolves, whichever comes first.
import { retry } from '@resolute/std/control';
await retry(fetch)('https://httpstat.us/200');
Promisify setTimeout
. Returns a Promise that settles with the return of the passed function after
delay
milliseconds.
import { sleep } from '@resolute/std/control';
await sleep(1000, (then) => Date.now() - then, Date.now());
// ~1000
Create and return a new promise along with its resolve and reject parameters. Especially useful when “promisifying” a callback style API.
import { defer } from '@resolute/std/control';
const [promise, resolve, reject] = defer();
addEventListener('success', resolve);
addEventListener('error', reject);
await promise;
Wrap a function that to be executed once. Subsequent calls will return the value of the first (and only) invocation.
import { once } from '@resolute/std/control';
let value = 0;
const incr = () => ++value;
once(incr)(); // 1
once(incr)(); // 1
incr(); // 2
once(incr)(); // 1
Limit the number of invocations of a given function (or different functions) within an interval window. Useful for avoiding API rate limits.
import { throttle } from '@resolute/std/control';
const throttled = throttle(1, 1_000)(async () => {});
await throttled();
await throttled(); // 1s later
Returns a function, that, as long as it continues to be invoked (.), will not be triggered (*). The
function will be called after it stops being called for threshold
milliseconds.
// /-- 10s --\ /-- 10s --\ /-- 10s --\
// . . . . . . . . . . . . . *
import { debounce } from '@resolute/std/control';
let state = 0;
const fn = (value: number) => state += value;
const debounced = debounce(fn, 50);
debounced(1);
debounced(1);
debounced(1);
// state === 1
Parse and stringify cookies. Methods available for DOM and service worker contexts.
Easing functions from easings.net.
Helpers for interacting with Request
and Response
objects.
Throw if value is not in list.
import { fetchOk } from '@resolute/std/http';
await fetchOk('https://httpstat.us/500'); // HttpError: HTTP 500 Error
Throw if value is not in list.
import { method } from '@resolute/std/http';
method(['GET', 'POST'])(new Request('/', { method: 'POST' })); // 'POST'
method(['GET', 'POST'])(new Request('/', { method: 'PUT' })); // HttpError: Method must be within [GET, POST]
Invoke the correct Request/Response body reading method (json/text/formData/arrayBuffer) based on the content-type header.
import { readBody } from '@resolute/std/http';
const body = await readBody(new Response());
Intl helpers.
Transform an array to a en/US grammar list.
import { conjunction } from '@resolute/std/intl';
conjunction('1'); // '1'
conjunction(['1', '2']); // '1 and 2'
conjunction(['1', '2', '3']); // '1, 2, and 3'
Ranging, scaling, random integers, and more.
Define a ranging function to calculate the number bound by min
and max
and a percent or fraction
(0 through 1). Note: percent
s (fractions) less than 0 or greater than 1 will return values outside
of the min
–max
range.
import { range } from '@resolute/std/math';
range(0, 10)(0.5); // 5
range(0, 10)(1.5); // 15
range(0, 10)(-0.5); // -5
Define a scaling function to calculate the percentage of value
relative to min
and max
.
import { scale } from '@resolute/std/math';
scale(0, 10)(5); // 0.5
scale(0, 10)(15); // 1.5
scale(0, 10)(-5); // -0.5
Define a clamping function to keep a value
bound to the min
and max
.
import { clamp } from '@resolute/std/math';
clamp(0, 1)(0.5); // 0.5
clamp(0, 1)(5); // 1
clamp(0, 1)(-5); // 0
Generate a scale for each member of an array with (optional) overlap
. Use with array.map() to
generate the divided scales.
import { divide } from '@resolute/std/math';
[1, 2, 3]
.map(divide())
.map(([value, scaler]) => [
scaler(0), // 0%
scaler(1 / 3), // 33%
scaler(2 / 3), // 66%
scaler(3 / 3), // 100%
]);
// [
// [ 0, 1, 2, 3 ], // 1
// [ -1, 0, 1, 2 ], // 2
// [ -2, -1, 0, 1 ] // 3
// ]
Generate a random number inclusively between min
and max
.
Generate a random number between min
(inclusively) and max
(exclusively).
Validate mime types and file extensions as well as convert from mime to extension and visa versa.
Convert a file extension to a mime type.
import { extToMime } from '@resolute/std/mime';
extToMime('avif'); // 'image/avif'
extToMime('.avif'); // 'image/avif'
extToMime('foo'); // TypeError “foo” is not a valid extension.
Convert a mime type to a file extension.
import { mimeToExt } from '@resolute/std/mime';
mimeToExt('image/avif'); // 'avif'
mimeToExt('text/html; charset=utf-8'); // 'html'
mimeToExt('foo/bar'); // TypeError “foo/bar” is not a valid mime type.
Miscellaneous utilities without a home.
Match the keys of a
to the values of b
by matching the values of a
to the keys of b
and
eliminate undefined/null values.
import { mapKeyAValB } from '@resolute/std/misc';
const a = { foo: 'a', bar: 'b', baz: 'c' };
const b = { a: 1, b: 2 };
mapKeyAValB(a, b); // { foo: 1, bar: 2 }
Match the keys of a
to the values of b
by matching the values of a
to the keys of b
and
eliminate undefined/null values.
import { mapKeys } from '@resolute/std/misc';
const a = { a: 'foo', b: 'bar', c: 'baz' };
const b = { a: 1, b: 2 };
mapKeys(a, b); // { foo: 1, bar: 2 }
Composite coerce function to fix the capitalization of proper nouns.
Composite coerce function to sanitize an email address.
Composite coerce function to sanitize and format a 10-digit US phone number.
Promise keeper utility.
Provides caching behavior to an expensive function. Can perform periodic background refresh.
.stale()
: sync return what is in the cache; throws if empty.get()
: async return cache or new invocation if cache is empty.fresh()
: async return a new invocation of the expensive function.start(delay)
: continuously invoke expensive function.stop()
: continuous invocation
import { keeper } from '@resolute/std/promise';
const expensive = async () => Math.random() ** Math.random();
const kept = keeper(expensive);
kept.stale(); // sync; throws because cache is empty
await kept.get(); // invokes expensive() because cache is empty
kept.stale(); // sync; returns the resolved value of expensive()
kept.fresh(); // forces a new expensive() invocation
TODO: document missing items