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
- Functions
- Types
Primitive
Builtin
DeepReadonly
DeepRequired
RequiredExcept
PartialRequired
ArgumentTypes
Arr
Ctor
AbstractCtor
Constructor
AbstractConstructor
FirstArgument
SecondArgument
Awaitable
Nullish
NonNullableProperties
NonNullObject
AnyObject
PrettifyObject
PickByValue
Mutable
StrictRequired
ArrayElementType
- Javascript Utilities
- Buy us some doughnuts
- Contributors
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 With | Address |
---|---|
Open Collective | Click Here |
Ko-fi | Click Here |
Patreon | Click Here |
PayPal | Click 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!