Skip to main content

Sapphire Logo

@sapphire/utilities

Common JavaScript utilities for the Sapphire Community.

GitHub npm bundle size npm

Table of Contents

Description

We often have a need for a function or type augmentation and having to include it in every repo is a huge drag. To solve this problem there are dozens upon dozens of packages on NPM, but we cannot maintain those in case of issues and a lot of them are poorly written or under-optimised. Our solution is to provide @sapphire/utilities, which is the only package you'll likely need to cover your day-to-day needs.

Features

  • Written in TypeScript
  • Bundled with esbuild so it can be used in NodeJS and browsers
  • Offers CommonJS, ESM and UMD bundles
  • Fully tested

Installation

You can use the following command to install this package, or replace npm install with your package manager of choice.

npm install @sapphire/utilities

Usage

You can import individual utility function from subpath like: @sapphire/utility/isFunction or the entire library.

import { isFunction } from '@sapphire/utilities/isFunction';
// or
import { isFunction } from '@sapphire/utilities';

Note: For typescript users, subpath import are only supported in --moduleResolution node16 and --moduleResolution nodenext. More information can be found in this issue on the microsoft/TypeScript repository.

Note: While this section uses require, the imports match 1:1 with ESM imports. For example const { arrayStrictEquals } = require('@sapphire/utilities') equals import { arrayStrictEquals } from '@sapphire/utilities'.

Javascript Utilities

arrayStrictEquals

Compares if two arrays are strictly equal.

arrayStrictEquals([1, 2, 3], [1, 2, 3]); // true
arrayStrictEquals([1, 2, 3], [1, 2, 3, 4]); // false
arrayStrictEquals([1, 2, 3], [1, 2, 4]); // false

chunk

Splits up an array into chunks.

chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
chunk([1, 2, 3, 4, 5], 3); // [[1, 2, 3], [4, 5]]

classExtends

Checks whether or not the value class extends the base class.

class A {}
class B extends A {}

classExtends(A, B); // false
classExtends(B, A); // true

codeBlock

Wraps text in a markdown codeblock with a language indicator for syntax highlighting.

codeBlock('js', 'const value = "Hello World!";'); // ```js\nconst value = "Hello World!";\n```

cutText

Split a text by its latest space character in a range from the character 0 to the selected one.

cutText('Lorem Ipsum', 9); // "Lorem..."

deepClone

Deep clones an object.

const obj = { a: 1, b: { c: 2 } };
const clone = deepClone(obj); // { a: 1, b: { c: 2 } }

filterNullAndUndefined

Checks whether a value is not null nor undefined. This can be used in Array#filter to remove null and undefined from the array type

// TypeScript Type: (string | undefined | null)[]
const someArray = ['one', 'two', undefined, null, 'five'];

// TypeScript Type: string[]
const filteredArray = someArray.filter(filterNullAndUndefined); // ['one', 'two', 'five']

filterNullAndUndefinedAndEmpty

Checks whether a value is not null, undefined, or '' (empty string). This can be used in Array#filter to remove null, undefined, and '' from the array type

// TypeScript Type: (number | string | undefined | null)[]
const someArray = [1, 2, undefined, null, ''];

// TypeScript Type: number[]
const filteredArray = someArray.filter(filterNullAndUndefinedAndEmpty); // [1, 2]

filterNullAndUndefinedAndZero

Checks whether a value is not null, undefined, or 0. This can be used in Array#filter to remove null, undefined, and 0 from the array type

// TypeScript Type: (string | number | undefined | null)[]
const someArray = ['one', 'two', undefined, null, 0];

// TypeScript Type: string[]
const filteredArray = someArray.filter(filterNullAndUndefinedAndZero); // ['one', 'two']

getDeepObjectKeys

Returns an array of all the keys of an object, including the keys of nested objects.

const obj = { a: 1, b: { c: 2 }, d: [{ e: 3 }] };
getDeepObjectKeys(obj); // ['a', 'b.c', 'd.0.e']
getDeepObjectKeys(obj, { arrayKeysIndexStyle: 'braces' }); // ['a', 'bc', 'd[0]e']
getDeepObjectKeys(obj, { arrayKeysIndexStyle: 'braces-with-dot' }); // ['a', 'b.c', 'd[0].e']
getDeepObjectKeys(obj, { arrayKeysIndexStyle: 'dotted' }); // ['a', 'b.c', 'd.0.e']

hasAtLeastOneKeyInMap

Checks whether a map has at least one of an array of keys.

const map = new Map([
['a', 1],
['b', 2],
['c', 3]
]);

hasAtLeastOneKeyInMap(map, ['a', 'd']); // true
hasAtLeastOneKeyInMap(map, ['d', 'e']); // false

inlineCodeBlock

Wraps text in a markdown inline codeblock.

inlineCodeBlock('const value = "Hello World!";'); // `const value = "Hello World!";`

isClass

Verifies if the input is a class constructor.

class A {}

isClass(A); // true
isClass(function () {}); // false

isFunction

Verifies if the input is a function.

isFunction(function () {}); // true
isFunction('foo'); // false

isNullOrUndefined

Checks whether a value is null or undefined.

isNullOrUndefined(null); // true
isNullOrUndefined(undefined); // true
isNullOrUndefined(1); // false

isNullOrUndefinedOrEmpty

Checks whether a value is null, undefined, or '' (empty string).

isNullOrUndefinedOrEmpty(null); // true
isNullOrUndefinedOrEmpty(undefined); // true
isNullOrUndefinedOrEmpty(''); // true
isNullOrUndefinedOrEmpty(1); // false

isNullOrUndefinedOrZero

Checks whether a value is null, undefined, or 0.

isNullOrUndefinedOrZero(null); // true
isNullOrUndefinedOrZero(undefined); // true
isNullOrUndefinedOrZero(0); // true
isNullOrUndefinedOrZero(1); // false

isNumber

Verifies if the input is a number.

isNumber(1); // true
isNumber('1'); // false

isObject

Verifies if the input is an object.

isObject({}); // true
isObject([]); // true
isObject('foo'); // false

isPrimitive

Verifies if the input is a primitive.

isPrimitive(1); // true
isPrimitive('1'); // true
isPrimitive({}); // false

isThenable

Verifies if an object is a promise.

isThenable({}); // false
isThenable(Promise.resolve()); // true

lazy

Lazily creates a constant or load a module and caches it internally.

let timesCalled = 0;
const lazyValue = lazy(() => {
timesCalled++;
return 'foo';
});

lazyValue(); // 'foo'
lazyValue(); // 'foo' - cached

timesCalled; // 1

makeObject

Turn a dotted path into a json object.

makeObject('a.b.c', 1); // { a: { b: { c: 1 } } }

mergeDefault

Deep merges two objects. Properties from the second parameter are applied to the first.

const base = { a: 1, b: { c: 2 } };
const overwritten = { b: { d: 3 } };

mergeDefault(base, overwritten);
overwritten; // { a: 1, b: { c: 2, d: 3 } }

mergeObjects

Merges two objects.

const source = { a: 1, b: 2 };
const target = { c: 4 };

mergeObjects(source, target);
target; // { a: 1, b: 2, c: 4 }

noop

A no-operation function.

noop(); // undefined

// Example usage of ignoring a promise rejection
Promise.reject().catch(noop);

objectToTuples

Converts an object to a tuple with string paths.

const obj = { a: 1, b: { c: 2 } };
objectToTuples(obj); // [['a', 1], ['b.c', 2]]

partition

Partitions an array into a tuple of two arrays, where one array contains all elements that satisfies the predicate, and the other contains all elements that do not satisfy the predicate.

const arr = [1, 2, 3, 4, 5];
const [evens, odds] = partition(arr, (n) => n % 2 === 0);

evens; // [2, 4]
odds; // [1, 3, 5]

pickRandom

Picks a random element from an array.

const arr = [1, 2, 3, 4, 5];
pickRandom(arr); // 3

range

Get an array of numbers with the selected range, considering a specified step.

range(1, 4, 1); // [1, 2, 3, 4]
range(1, 4, 2); // [1, 3]
range(4, 1, -1); // [4, 3, 2, 1]
range(4, 1, -2); // [4, 2]

regExpEsc

Cleans a string from regex injection by escaping special characters.

regExpEsc('foo.bar?'); // 'foo\\.bar\\?'

roundNumber

Properly rounds up or down a number. Also supports strings using an exponent to indicate large or small numbers.

roundNumber(1.9134658034); // 1
roundNumber(1.9134658034, 2); // 1.91
roundNumber('10e-5'); // 0

sleep / sleepSync

Sleeps for the specified number of milliseconds.

await sleep(1000); // Sleeps for 1 second
sleepSync(1000); // Sleeps for 1 second

splitText

Split a string by its latest space character in a range from the character 0 to the selected one.

splitText('Hello All People!', 8); // 'Hello'
splitText('Hello All People!', 10); // 'Hello All'

throttle

Creates a throttled function that only invokes a function at most once per every x milliseconds. The throttled function comes with a flush method to reset the last time the throttled function was invoked.

const throttled = throttle(() => console.log('throttled'), 1000);

throttled(); // 'throttled'
throttled(); // nothing
throttled.flush();
throttled(); // 'throttled'

toTitleCase

Converts a string to Title Case. This is designed to also ensure common Discord PascalCased strings are put in their TitleCase variants.

toTitleCase('foo bar'); // 'Foo Bar'
toTitleCase('textchannel'); // 'TextChannel'
toTitleCase('onetwo three', { onetwo: 'OneTwo' }); // OneTwo Three

tryParseJSON

Tries to parse a string as JSON.

tryParseJSON('{"foo": "bar"}'); // { foo: 'bar' }
tryParseJSON('{"foo": "bar"' /* invalid */); // '{"foo": "bar"'

tryParseURL

Tries to parse a string as a URL.

tryParseURL('https://google.com'); // URL object
tryParseURL('hello there :)'); // null

Typescript Utilities

A subset of our utilities are intended specifically for typescript users.

Functions

cast

Casts any value to T. Note that this function is not type-safe, and may cause runtime errors if used incorrectly.

const value = cast<string>(1); // value is now of type string
objectEntries

A strongly-typed alternative to Object.entries.

const obj = { a: 1, b: 2 } as const;

const native = Object.entries(obj); // [string, number][]
const strict = objectEntries(obj); // [['a', 1], ['b', 2]]
objectKeys

A strongly-typed alternative to Object.keys.

const obj = { a: 1, b: 2 } as const;

const native = Object.keys(obj); // string[]
const strict = objectKeys(obj); // ['a', 'b']
objectValues

A strongly-typed alternative to Object.values.

const obj = { a: 1, b: 2 } as const;

const native = Object.values(obj); // number[]
const strict = objectValues(obj); // [1, 2]

Types

Primitive

A union of all primitive types.

// string | number | bigint | boolean | symbol | undefined | null
declare const primitive: Primitive;
Builtin

A union of all builtin types.

// Primitive | Function | Date | Error | RegExp
declare const builtin: Builtin;
DeepReadonly

Makes all properties in T readonly recursively.

type Foo = Set<{ bar?: ['foo', { hello: 'world' }] }>;

// ReadonlySet<{
// readonly bar?: readonly ["foo", {
// readonly hello: "world";
// }] | undefined;
// }>
declare const foo: DeepReadonly<Foo>;
DeepRequired

Makes all properties in T required recursively.

type Foo = Set<{ bar?: Promise<{ baz?: string }>[] }>;

// Set<{ bar: Promise<{ baz: string }>[] }>
declare const foo: DeepRequired<Foo>;
RequiredExcept

Makes all properties in T required except for the ones specified in K.

interface Foo {
bar?: string;
baz?: number;
}

// { bar?: string; baz: number }
declare const foo: RequiredExcept<Foo, 'bar'>;
PartialRequired

Makes all properties in T that are assignable to K required.

interface Foo {
bar?: string;
baz?: number;
}

// { bar: string; baz?: number }
declare const foo: PartialRequired<Foo, 'bar'>;
ArgumentTypes

Extracts the argument types of a function type.

type Foo = (bar: string, baz: number) => void;

// [string, number]
declare const foo: ArgumentTypes<Foo>;
Arr

A type that represents a readonly array of any.

// readonly any[]
declare const arr: Arr;
Ctor

A constructor with parameters.

// new (...args: any[]) => any
declare const foo: Ctor;

// new (...args: [string, number]) => SomeClass
declare const bar: Ctor<[string, number], SomeClass>;
AbstractCtor

An abstract constructor with parameters.

// abstract new (...args: any[]) => any
declare const foo: AbstractCtor;

// abstract new (...args: [string, number]) => SomeClass
declare const bar: AbstractCtor<[string, number], SomeClass>;
Constructor

A constructor without parameters.

// new (...args: any[]) => any
declare const foo: Constructor;

// new (...args: any[]) => SomeClass
declare const bar: Constructor<SomeClass>;
AbstractConstructor

An abstract constructor without parameters.

// abstract new (...args: any[]) => any
declare const foo: AbstractConstructor;

// abstract new (...args: any[]) => SomeClass
declare const bar: AbstractConstructor<SomeClass>;
FirstArgument

Extracts the first argument of a function type.

type Foo = (bar: string, baz: number) => void;

// string
declare const foo: FirstArgument<Foo>;
SecondArgument

Extracts the second argument of a function type.

type Foo = (bar: string, baz: number) => void;

// number
declare const foo: SecondArgument<Foo>;
Awaitable

A type that represents a value or a promise of a value. Useful for functions that can accept both promises and non-promises.

// string | Promise<string>
declare const foo: Awaitable<string>;
Nullish

A type that represents null or undefined.

// null | undefined
declare const foo: Nullish;
NonNullableProperties

Removes all properties of T that are not null or undefined.

interface Foo {
foo: null;
bar: undefined;
baz: boolean;
}

// { baz: boolean }
declare const foo: NonNullableProperties<Foo>;
NonNullObject (deprecated)

A type that represents an object that is not null or undefined.

// ✅
const foo: NonNullObject = {};

// ❌
const bar: NonNullObject = null;

// ❌
const baz: NonNullObject = undefined;
AnyObject (deprecated)

An object that can have any structure. Similar to NonNullObject, and to be used as an alternative if the aforementioned type leads to unexpected behaviors.

// ✅
const foo: AnyObject = {};

// ❌
const bar: AnyObject = null;

// ❌
const baz: AnyObject = undefined;
PrettifyObject

An utility type that fuses intersections of objects.

type Objects = {
foo: string;
bar: number;
} & {
hello: boolean;
world: bigint;
};

type PrettyObjects = PrettifyObject<Objects>;
// {
// foo: string;
// bar: number;
// hello: boolean;
// world: bigint
// }
PickByValue

Picks keys from T who's values are assignable to V.

interface Foo {
foo: string;
bar: number;
baz: boolean;
}

// 'foo' | 'bar'
declare const foo: PickByValue<Foo, string | number>;
Mutable

Makes all properties in T mutable.

interface Foo {
readonly bar: string;
readonly baz: readonly number][];
}

// { bar: string; baz: number[] }
declare const foo: Mutable<Foo>;
StrictRequired

Makes all properties in T strictly required by removing undefined and null from value types.

interface Foo {
bar: string | undefined;
baz?: number | null;
}

// { bar: string; baz: number }
declare const foo: StrictRequired<Foo>;
ArrayElementType

Gets a union type of all the keys that are in an array.

const sample = [1, 2, '3', true];

// string | number | boolean
declare const foo: ArrayElementType<typeof sample>;

Buy us some doughnuts

Sapphire Community is and always will be open source, even if we don't get donations. That being said, we know there are amazing people who may still want to donate just to show their appreciation. Thank you very much in advance!

We accept donations through Open Collective, Ko-fi, Paypal, Patreon and GitHub Sponsorships. You can use the buttons below to donate through your method of choice.

Donate WithAddress
Open CollectiveClick Here
Ko-fiClick Here
PatreonClick Here
PayPalClick Here

Contributors

Please make sure to read the Contributing Guide before making a pull request.

Thank you to all the people who already contributed to Sapphire!

Interfaces

InterfaceDescription
DebouncedFuncCall the original function, but applying the debounce rules.
DebounceSettingslodash (Custom Build) https://lodash.com/ Build: lodash modularize exports="npm" -o ./ Copyright jQuery Foundation and other contributors https://jquery.org/ Released under MIT license https://lodash.com/license Based on Underscore.js 1.8.3 http://underscorejs.org/LICENSE Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
GetDeepObjectKeysOptionsThe options for getDeepObjectKeys
PollOptionsThe options for the poll function
SleepOptions-
SyncPollOptionsThe options for the pollSync function
Thenable-
ToTitleCaseOptionsThe options to use when converting a string to title case

Type Aliases

Type AliasDescription
AbstractConstructorA generic abstract constructor without parameters
AbstractCtorA generic abstract constructor with parameters
AnyObjectAn object that can have any structure, this is an alternative to NonNullObject for situations where that leads to unexpected type resolutions.
AnyReadonlyArrayA readonly array of any values.
ArgumentTypes-
ArrayElementTypeGets a union type of all the keys that are in an array.
AwaitableReturnType for a function that can return either a value or a Promise with that value
Builtin-
ConstructorA generic constructor without parameters
CtorA generic constructor with parameters
DeepPartial-
DeepReadonly-
DeepRequired-
FirstArgumentGets the first argument of any given function
IfA type utility that allows branching of types depending on the Value parameter.
MutableTransforms a readonly type to be mutable
NonNullablePropertiesSimilar to the built in NonNullable, but properly removes null from all keys in the class or interface This does not recurse deeply, for that use DeepRequired
NonNullObjectAn object that is non nullable, to bypass TypeScript not easily working with Record<PropertyKey, unknown> in various instances.
NullishType union for the full 2 billion dollar mistake in the JavaScript ecosystem
PartialRequired-
PickByValueGets all the keys (as a string union) from a type T that match value V
PrettifyObjectAn utility type that fuses intersections of objects.
Primitive-
RequiredExcept-
RequiredIfA type utility that allows branching of an union type on the Value parameter.
SecondArgumentGets the second argument of any given function
StrictRequiredTransforms every key in an object to be strictly required, essentially removing undefined and null from the type.
ThrottleFn-

Variables

VariableDescription
toTitleCaseDiscordJsVariantsThe variants that will not strictly follow the toTitleCase algorithm and will instead return the value matched with the key.

Functions

FunctionDescription
arrayStrictEqualsCompare if both arrays are strictly equal
capitalizeFirstLetterTransforms the first letter to a capital then adds all the rest after it
castCasts any value to T
chunkSplits up an array into chunks
classExtendsChecks whether or not the value class extends the base class.
codeBlockWraps the content inside a codeblock with no language
cutText-
debounceCreates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked. The debounced function comes with a cancel method to cancel delayed invocations and a flush method to immediately invoke them. Provide an options object to indicate that func should be invoked on the leading and/or trailing edge of the wait timeout. Subsequent calls to the debounced function return the result of the last func invocation.
deepCloneDeep clone an object
filterNullAndUndefinedChecks whether a value is not null nor undefined. This can be used in Array.filter to remove null and undefined from the array type
filterNullAndUndefinedAndEmptyChecks whether a value is not null nor undefined nor '' (empty string). This can be used in Array.filter to remove null, undefined from the array type
filterNullAndUndefinedAndZeroChecks whether a value is not null nor undefined nor 0. This can be used in Array.filter to remove null, undefined from the array type
getDeepObjectKeysFlattens an object to a list of its keys, traversing deeply into nested objects and arrays of objects.
hasAtLeastOneKeyInMapChecks whether any of the keys are in the map
hasAtLeastOneKeyInObjectChecks whether any of the keys are in the obj
inlineCodeBlockWraps text in a markdown inline codeblock
isClassVerify if the input is a class constructor.
isFunctionVerify if the input is a function.
isNullOrUndefinedChecks whether or not a value is null or undefined
isNullOrUndefinedOrEmptyChecks whether or not a value is null, undefined or '', []
isNullOrUndefinedOrZeroChecks whether or not a value is null, undefined or 0
isNumberVerify if a number is a finite number.
isObjectVerify if the input is an object literal (or class).
isPrimitiveCheck whether a value is a primitive
isThenableVerify if an object is a promise.
lazyLazily creates a constant or load a module and caches it internally
makeObjectTurn a dotted path into a json object.
mergeDefaultDeep merges 2 objects. Properties from the second parameter are applied to the first.
mergeObjectsMerges two objects
noop-
objectEntries-
objectKeys-
objectToTuplesConvert an object to a tuple
objectValues-
omitKeysFromObjectClones the source object using deepClone then deletes the specified keys with Reflect.deleteProperty
partitionPartitions array into a tuple of two arrays, where one array contains all elements that satisfies predicate, and the other contains all elements that do not satisfy predicate.
pickRandomPicks a random element from an array
pollExecutes a function cb and validates the result with function cbCondition, and repeats this until cbCondition returns true or the timeout is reached.
pollSyncExecutes a function cb and validates the result with function cbCondition, and repeats this until cbCondition returns true or the timeout is reached.
rangeGet an array of numbers with the selected range
regExpEscCleans a string from regex injection
retryAsynchronously calls the callback function until it either succeeds or it runs out of retries. For a synchronous variant, see retrySync.
retrySyncSynchronously calls the callback function until it either succeeds or it runs out of retries. For an asynchronous variant, see retry.
roundNumberRounds a number to a specified amount of decimal places.
sleepSleeps for the specified number of milliseconds. For a synchronous variant, see sleepSync.
sleepSyncSleeps for the specified number of milliseconds synchronously. We should probably note that unlike sleep (which uses CPU tick times), sleepSync uses wall clock times, so the precision is near-absolute by comparison. That, and that synchronous means that nothing else in the thread will run for the length of the timer.
snakeToCamelCaseTransforms text from snAkE_cASE to camelCase.
splitText-
throttleCreates a throttled function that only invokes func at most once per every wait milliseconds. The throttled function comes with a flush method to reset the last time the throttled function was invoked.
toTitleCaseConverts a string to Title Case
tryParseJSONTry parse a stringified JSON string.
tryParseURLTries parse a string to a URL object

References

filterNullish

Renames and re-exports filterNullAndUndefined


filterNullishAndEmpty

Renames and re-exports filterNullAndUndefinedAndEmpty


filterNullishAndZero

Renames and re-exports filterNullAndUndefinedAndZero


filterNullishOrEmpty

Renames and re-exports filterNullAndUndefinedAndEmpty


filterNullishOrZero

Renames and re-exports filterNullAndUndefinedAndZero


isNullish

Renames and re-exports isNullOrUndefined


isNullishOrEmpty

Renames and re-exports isNullOrUndefinedOrEmpty


isNullishOrZero

Renames and re-exports isNullOrUndefinedOrZero


kebabToCamelCase

Renames and re-exports snakeToCamelCase


parseURL

Renames and re-exports tryParseURL


tryParse

Renames and re-exports tryParseJSON