Skip to main content

@pexip/utils

Generic utility functions.

Install

npm install @pexip/utils

Table of Content

Functions

Wrap or create new functions.

noop

Placeholder function, useful when we're expecting a function to be set later

import {noop} from '@pexip/utils';

noop(); // returns undefined

let fn: () => void = noop;

onEvent(() => {
fn(); // won't fail even if this is called before onUpdate
});

onUpdate((updatedFn: () => void) => {
fn = updatedFn;
});

pipe

Pipes the value of an expression into a pipeline of functions.

import {pipe} from '@pexip/utils';

const len = (s: string): number => s.length;
const double = (n: number): number => n * 2;

// Equivalent to `const doubleLen = (s: string) => double(len(s));`
const doubleLen = pipe(len, double);

doubleLen('abc'); // returns 6

throttle

Creates a throttled function that only invokes func at most once per every wait milliseconds

import {throttle} from '@pexip/utils';

const onMouseMoveCallback = () => {
// do some logic on 🐭 move
};

const throttled = throttle(onMouseMoveCallback, 500);

document.addEventListener('mousemove', throttled); // onMouseMoveCallback will invoke only once within a 500 milliseconds

isDefined

Test that a value t is set to something and return it, throws on undefined. This is handy when selecting using an index to eliminiate the infered undefined type.

import {isDefined} from '@pexip/utils';

const strs = ['foo', 'bar', 'qux'];
// str infers `string`, or throws if selecting outside range
const str = isDefined(strs[0]);

const objs: {[key: string]: {prop: string}} = {
hello: {prop: 'world'};
}
// obj infers `{prop: string}`, or throws if the key is not set
const obj = isDefined(objs['hello'])

try {
console.log(isDefined('')); // => ''
console.log(isDefined(0)); // => 0
console.log(isDefined(false)); // => false
console.log(isDefined(null)); // => null
console.log(isDefined(undefined)); // will throw
// ...

Array

nthThrows

Inspired by lodash nth this will select the given index from an array, but throw if the selected value is undefined. As with the lodash version of nth it will select from the end of the array given a negative index. This version of nth is likely to be most useful in tests.

import {nthThrows} from '@pexip/utils';

const mockData = [{foo: 'bar'}];

describe('test suite', () => {
it('should test something', () => {
// this will be {foo: string} | undefined
const dataOrUndefined = mockData[0]:
// while this will be {foo: string}, or else the test will fail
const data = nthThrows(mockData, 0);
});
})

nthOr

Inspired by lodash nth this will select the given index from an array, but return the default value if the selected value is undefined. As with the lodash version of nth it will select from the end of the array given a negative index.

import {nthOr} from '@pexip/utils';

const nrs = [10, 20, 30];
console.log(nthOr(nrs, 0, 40)); // => 10
console.log(nthOr(nrs, 1, 40)); // => 20
console.log(nthOr(nrs, 2, 40)); // => 30
console.log(nthOr(nrs, 3, 40)); // => 40
console.log(nthOr(nrs, -1, 40)); // => 30
console.log(nthOr(nrs, -2, 40)); // => 20
console.log(nthOr(nrs, -3, 40)); // => 10
console.log(nthOr(nrs, -4, 40)); // => 40

It is generic and will infer what type it expects as a defaultValue.

const values = [
{foo: 'bar', baz: 10, qux: [10]},
{foo: 'quux', qux: []},
];
const value = nthOr(values, 0, {foo: '', qux: []}); // it should know that `foo` and `qux` are required fields

firstOr and lastOr

Quite commonly we want either the first or last value from an array, so these wrap nthOr with a default index parameter.

import {firstOr, lastOr} from '@pexip/utils';

const strs = ['foo', 'bar', 'qux'];
console.log(firstOr(strs, '')); // => 'foo';
console.log(lastOr(strs, '')); // => 'qux';

Backoff

Exponential backoff utility class. Usage as so:

import {Backoff} from '@pexip/utils';

const backoff = new Backoff({
factor: 2,
jitter: 0,
max: 30000,
min: 1000,
});

for (let i = 0; i < MAX_REFRESH_ATTEMPTS; i++) {
const attempt = Boolean(Math.round(Math.random())); //try something

if (attempt) {
backoff.reset();
return;
} else {
await backoff.promise();
}
}
backoff.reset();

endsWithAnyOf

like String.endsWith but allows passing an array of search strings (instead of just 1), returning true if the 'subject' string matches any of them.

import {endsWithAnyOf} from '@pexip/utils';

const doesEndWith = endsWithAnyOf('Pexip', ['hello', 'ip', '!']); //true
const doesEndWith2 = endsWithAnyOf('Pexip', ['hello', 'world', '!']); //false

getBaseURI

get the base path of document

<base href="/somepath/" />
import {getBaseURI} from '@pexip/utils';

const base = getBaseURI(); // /somepath/