Table of Contents
- Description
- Features
- Installation
-
Usage
-
Javascript Utilities
arrayStrictEquals
chunk
classExtends
codeBlock
cutText
deepClone
filterNullAndUndefined
filterNullAndUndefinedAndEmpty
filterNullAndUndefinedAndZero
getDeepObjectKeys
hasAtLeastOneKeyInMap
inlineCodeBlock
isClass
isFunction
isNullOrUndefined
isNullOrUndefinedOrEmpty
isNullOrUndefinedOrZero
isNumber
isObject
isPrimitive
isThenable
lazy
makeObject
mergeDefault
mergeObjects
noop
objectToTuples
partition
pickRandom
range
regExpEsc
roundNumber
sleep
/sleepSync
splitText
throttle
toTitleCase
tryParseJSON
tryParseURL
- Typescript Utilities
-
Javascript Utilities
- Buy us some doughnuts
- Contributors
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.
- Written in TypeScript
- Bundled with esbuild so it can be used in NodeJS and browsers
- Offers CommonJS, ESM and UMD bundles
- Fully tested
You can use the following command to install this package, or replace npm install
with your package manager of choice.
npm install @sapphire/utilities
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'
.
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
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]]
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
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```
Split a text by its latest space character in a range from the character 0 to the selected one.
cutText('Lorem Ipsum', 9); // "Lorem..."
Deep clones an object.
const obj = { a: 1, b: { c: 2 } };
const clone = deepClone(obj); // { a: 1, b: { c: 2 } }
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']
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]
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']
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']
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
Wraps text in a markdown inline codeblock.
inlineCodeBlock('const value = "Hello World!";'); // `const value = "Hello World!";`
Verifies if the input is a class constructor.
class A {}
isClass(A); // true
isClass(function () {}); // false
Verifies if the input is a function.
isFunction(function () {}); // true
isFunction('foo'); // false
Checks whether a value is null
or undefined
.
isNullOrUndefined(null); // true
isNullOrUndefined(undefined); // true
isNullOrUndefined(1); // false
Checks whether a value is null
, undefined
, or ''
(empty string).
isNullOrUndefinedOrEmpty(null); // true
isNullOrUndefinedOrEmpty(undefined); // true
isNullOrUndefinedOrEmpty(''); // true
isNullOrUndefinedOrEmpty(1); // false
Checks whether a value is null
, undefined
, or 0
.
isNullOrUndefinedOrZero(null); // true
isNullOrUndefinedOrZero(undefined); // true
isNullOrUndefinedOrZero(0); // true
isNullOrUndefinedOrZero(1); // false
Verifies if the input is a number.
isNumber(1); // true
isNumber('1'); // false
Verifies if the input is an object.
isObject({}); // true
isObject([]); // true
isObject('foo'); // false
Verifies if the input is a primitive.
isPrimitive(1); // true
isPrimitive('1'); // true
isPrimitive({}); // false
Verifies if an object is a promise.
isThenable({}); // false
isThenable(Promise.resolve()); // true
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
Turn a dotted path into a json object.
makeObject('a.b.c', 1); // { a: { b: { c: 1 } } }
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 } }
Merges two objects.
const source = { a: 1, b: 2 };
const target = { c: 4 };
mergeObjects(source, target);
target; // { a: 1, b: 2, c: 4 }
A no-operation function.
noop(); // undefined
// Example usage of ignoring a promise rejection
Promise.reject().catch(noop);
Converts an object to a tuple with string paths.
const obj = { a: 1, b: { c: 2 } };
objectToTuples(obj); // [['a', 1], ['b.c', 2]]
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]
Picks a random element from an array.
const arr = [1, 2, 3, 4, 5];
pickRandom(arr); // 3
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]
Cleans a string from regex injection by escaping special characters.
regExpEsc('foo.bar?'); // 'foo\\.bar\\?'
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
Sleeps for the specified number of milliseconds.
await sleep(1000); // Sleeps for 1 second
sleepSync(1000); // Sleeps for 1 second
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'
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'
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
Tries to parse a string as JSON.
tryParseJSON('{"foo": "bar"}'); // { foo: 'bar' }
tryParseJSON('{"foo": "bar"' /* invalid */); // '{"foo": "bar"'
Tries to parse a string as a URL.
tryParseURL('https://google.com'); // URL object
tryParseURL('hello there :)'); // null
A subset of our utilities are intended specifically for typescript users.
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
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]]
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']
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]
A union of all primitive types.
// string | number | bigint | boolean | symbol | undefined | null
declare const primitive: Primitive;
A union of all builtin types.
// Primitive | Function | Date | Error | RegExp
declare const builtin: Builtin;
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>;
Makes all properties in T
required recursively.
type Foo = Set<{ bar?: Promise<{ baz?: string }>[] }>;
// Set<{ bar: Promise<{ baz: string }>[] }>
declare const foo: DeepRequired<Foo>;
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'>;
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'>;
Extracts the argument types of a function type.
type Foo = (bar: string, baz: number) => void;
// [string, number]
declare const foo: ArgumentTypes<Foo>;
A type that represents a readonly array of any
.
// readonly any[]
declare const arr: Arr;
A constructor with parameters.
// new (...args: any[]) => any
declare const foo: Ctor;
// new (...args: [string, number]) => SomeClass
declare const bar: Ctor<[string, number], SomeClass>;
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>;
A constructor without parameters.
// new (...args: any[]) => any
declare const foo: Constructor;
// new (...args: any[]) => SomeClass
declare const bar: Constructor<SomeClass>;
An abstract constructor without parameters.
// abstract new (...args: any[]) => any
declare const foo: AbstractConstructor;
// abstract new (...args: any[]) => SomeClass
declare const bar: AbstractConstructor<SomeClass>;
Extracts the first argument of a function type.
type Foo = (bar: string, baz: number) => void;
// string
declare const foo: FirstArgument<Foo>;
Extracts the second argument of a function type.
type Foo = (bar: string, baz: number) => void;
// number
declare const foo: SecondArgument<Foo>;
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>;
A type that represents null
or undefined
.
// null | undefined
declare const foo: Nullish;
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>;
A type that represents an object that is not null
or undefined
.
// ✅
const foo: NonNullObject = {};
// ❌
const bar: NonNullObject = null;
// ❌
const baz: NonNullObject = undefined;
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;
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>;
Makes all properties in T
mutable.
interface Foo {
readonly bar: string;
readonly baz: readonly number][];
}
// { bar: string; baz: number[] }
declare const foo: Mutable<Foo>;
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>;
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>;
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 With | Address |
---|---|
Open Collective | Click Here |
Ko-fi | Click Here |
Patreon | Click Here |
PayPal | Click Here |
Please make sure to read the Contributing Guide before making a pull request.
Thank you to all the people who already contributed to Sapphire!