Modular, tree-shakable, zero-dependency TypeScript utility library — v5.0.0
npm install @slck/utils
Each submodule can be imported independently for optimal tree-shaking:
import { isNil, isEmpty } from '@slck/utils/guards';
import { toCamelCaseKeys } from '@slck/utils/transforms';
import { objectDifferenceByProps } from '@slck/utils/comparators';
import { shiftToFirst, filterTree } from '@slck/utils/collections';
import { timeFromSeconds, padZero } from '@slck/utils/formatters';
import { normalizeUrl } from '@slck/utils/paths';
import { parseSqlCustomExpressionTokens } from '@slck/utils/sql';
import { randomColor } from '@slck/utils/color';
import type { EndpointConfig } from '@slck/utils/types';
Or import everything at once:
import { isNil, shiftToFirst, randomColor } from '@slck/utils';
| Function |
Description |
isNil(value) |
true if null or undefined |
isDate(value) |
true if a valid Date object or parseable string/number |
isDateLike(value) |
true if an ISO 8601 string (YYYY-MM-DD…) or Date instance |
isObject(value) |
true if a non-null, non-array object |
isEmpty(value) |
true if null, undefined, empty string, array, or object |
isNilOrEmpty(value) |
true if isNil or isEmpty |
isEmptyInDepth(value) |
true if all own properties are falsy / empty |
hasValidLength(value) |
true if the value has a numeric length property |
hasValidDate(date) |
true if the date is not the .NET default 0001-01-01T00:00:00 |
isEndpointConfig(value) |
Type guard for EndpointConfig shape |
import { isNil, isNilOrEmpty, isDateLike } from '@slck/utils/guards';
isNil(null);
isNilOrEmpty(' ');
isDateLike('2024-06-01');
| Function |
Description |
toCamelCaseKeys(obj) |
Recursively lowercases first letter of all keys; overloaded for single object or array |
deepClone(value) |
JSON-based deep clone. Date objects become ISO strings |
trimObjectValues(obj) |
Recursively trims all string values; handles circular references |
addSpacesToCamelCase(str) |
Inserts a space before each uppercase letter |
initials(text, sep?) |
Extracts uppercased first letter from each word |
toReadableTitle(value, acronyms?) |
Converts camelCase/PascalCase/snake_case/kebab-case to Title Case |
isPalindrome(str) |
true if the string reads the same forwards and backwards |
toTitleCase(str) |
Capitalises the first letter of every word |
toSentenceCase(str) |
Lowercases the string and capitalises only the first character |
formatHeader(field) |
Converts a field name (camelCase/snake_case) to a human-readable header |
insertSpacesBetween(value) |
Splits camelCase/PascalCase into Title Case words |
normalizeString(val) |
Coerces to a trimmed, lowercased string; returns '' for null/undefined |
safeNumber(val) |
Coerces to a number; returns 0 for NaN |
splitByComma(input) |
Splits a comma-separated string into a trimmed, non-empty array |
toMinutes(hours, minutes) |
Converts hours + minutes into total minutes |
import { toCamelCaseKeys, toReadableTitle, splitByComma } from '@slck/utils/transforms';
toCamelCaseKeys({ FirstName: 'Ada' });
toCamelCaseKeys([{ UserId: 1 }]);
toReadableTitle('userFirstName');
toReadableTitle('apiUrl', ['API']);
splitByComma('a, b, , c');
| Function |
Description |
objectDifferenceByProps(src, dest) |
Returns symmetric property-level diffs between two objects |
compareObjectArrays(arr1, arr2) |
Validates that two arrays have structurally compatible objects (same keys + types); does not compare values |
extractCommonAndDifferentValues(objects, opts?) |
Deep multi-object comparison — returns { same, diff } |
hasDuplicateByKeys(arr, ...keys) |
true if any two items share identical values for the given keys |
isAnyRecordWithEmptyValues(records, keys, skip?) |
true if any record has an empty value for the given keys |
import { objectDifferenceByProps, hasDuplicateByKeys } from '@slck/utils/comparators';
objectDifferenceByProps({ a: 1, b: 2 }, { a: 1, b: 3, c: 4 });
hasDuplicateByKeys([{ id: 1 }, { id: 2 }, { id: 1 }], 'id');
| Function |
Description |
shiftToFirst(items, key, value, ci?) |
Moves the first matching item to index 0; returns a new array |
selectMatchingByKeys(src, sel, srcKey, matchKey) |
Filters source array to items whose key exists in the selection array |
existsInCollection(obj, collection, prop) |
true if the object's property value is found in the collection |
multiplesInRange(start, end, multiple) |
Returns all multiples of multiple within [start, end] |
buildTree(data, childrenKey, valueKey, nodeValueKey, delim?) |
Builds a nested tree from a flat array using a delimiter-based path key |
keyValueObject(key, value) |
Creates a single-key typed object |
filterTree(nodes, text, keys, childrenKey?, expandMatched?) |
Recursively filters a tree; pass expandMatched: false to skip UI state injection |
import { shiftToFirst, filterTree, multiplesInRange } from '@slck/utils/collections';
shiftToFirst([{ id: 1 }, { id: 2 }, { id: 3 }], 'id', 3);
multiplesInRange(1, 20, 5);
filterTree(tree, 'admin', ['label'], 'children', false);
| Function |
Description |
timeFromSeconds(seconds) |
Returns { days, hours, minutes, seconds } |
timeBetweenDates(start, end) |
Time remaining between two dates; null if end ≤ start |
minutesToTimeText(min, hourUnit, minUnit) |
Formats minutes as '2 h 10 min' |
padZero(value) |
Pads a number with a leading zero if < 10 |
numberToText(num) |
Converts an integer to English text ('one thousand two hundred'). Max: safe integer (~9e15) |
import { timeFromSeconds, numberToText, padZero } from '@slck/utils/formatters';
timeFromSeconds(3661);
numberToText(1042);
padZero(7);
| Function |
Description |
extractFileName(path) |
Extracts filename from a Windows or Unix path |
buildHierarchy(segments, sep?) |
Joins non-empty segments with a separator (default: ' > ') |
normalizeUrl(url) |
Normalises absolute, hash-based, and relative URLs to an app-relative path |
toComparableUrl(url) |
Strips query string and hash for route matching |
buildIncrementalWindowsPaths(path) |
Returns all cumulative Windows path segments for a given path |
import { extractFileName, normalizeUrl, buildHierarchy } from '@slck/utils/paths';
extractFileName('C:\\Users\\docs\\report.pdf');
normalizeUrl('https://example.com/app/home');
buildHierarchy(['Project', null, 'Task']);
Parses a token stream into a typed AST with full error reporting.
| Export |
Description |
parseSqlCustomExpressionTokens(tokens) |
Parses tokens into { valid: true, ast } or { valid: false, errors } |
buildExpressionToken(raw) |
Builds a typed SQLCustomToken from a raw value |
evaluateReturnTypeFromTokens(tokens) |
Returns the expression's return type from the first token |
isSQLFunctionToken(token, list) |
true if the token is a known SQL function |
SQL_FUNCTION_NAMES |
['SUM', 'AVG', 'ROUND', 'RATIO', 'CONCAT', 'COUNT', 'MIN', 'MAX', 'DATEDIFF'] |
MSSQL_DATEDIFF_PARTS |
Valid MSSQL DATEDIFF date parts |
import { parseSqlCustomExpressionTokens, buildExpressionToken } from '@slck/utils/sql';
const tokens = [
{ key: 'SUM', value: 'SUM' },
{ key: '(', value: '(' },
{ key: 'amount', value: 'amount', dataType: 'float' },
{ key: ')', value: ')' },
];
const result = parseSqlCustomExpressionTokens(tokens);
| Function |
Description |
randomColor() |
Returns a random hex color string (excludes #000000 and #ffffff) |
import { randomColor } from '@slck/utils/color';
randomColor();
import type {
GenericObjectType,
ErrorType,
HttpVerb,
PathQueryParams,
EndpointConfig,
EndpointRegistry,
LegacyEndpointConfig,
UnCapitalizeObjectKeys,
CompareOptions,
ApiResponse,
PaginatedResponse,
SortDescriptor,
FilterDescriptor,
ListQueryParams,
} from '@slck/utils/types';
All deprecated aliases still work but will be removed in a future major version.
| Deprecated |
Replacement |
isNullOrUndefined |
isNil |
isNullOrUndefinedEmpty |
isNilOrEmpty |
objectNonShadowCopy |
deepClone |
daysTimeFromSeconds |
timeFromSeconds |
remainingDaysHoursFormTwoDates |
timeBetweenDates |
convertMinutesToTimeText |
minutesToTimeText |
leadZeroForMonthOrDay |
padZero |
convertFirstLetterToUpper |
initials |
shiftToFristWith |
shiftToFirst |
selectMatchingObjectsByKeys |
selectMatchingByKeys |
checkObjectPropValueExistsInCollection |
existsInCollection |
generateMultiplesInRange |
multiplesInRange |
constructTreeRecursively |
buildTree |
genericObjectTypeFn |
keyValueObject |
compareObjectArraysWithTypeSafe |
compareObjectArrays |
generateRandomColorFn |
randomColor |
buildExpressionTokenFromPlain |
buildExpressionToken |
buildIncrementalPaths |
buildIncrementalWindowsPaths |
MIT Chandra Sekhar A