@mj-studio/js-util
v1.1.24
Published
Custom JavaScript Utilities for MJ Studio
Downloads
20,683
Readme
@mj-studio/js-util
A comprehensive collection of JavaScript utility functions for modern development. Written in TypeScript with full type safety and extensive JSDoc documentation.
Installation
yarn add @mj-studio/js-util
npm install @mj-studio/js-utilAPI Reference
String
camelCase(str: string): string
Converts a snake_case or kebab-case string to camelCase
camelCase('user_name') // Returns: 'userName'
camelCase('user-name') // Returns: 'userName'capitalize(str: string): string
Capitalizes the first character of a string
capitalize('hello') // Returns: 'Hello'
capitalize('hello world') // Returns: 'Hello world'lastMatchIndex(str: string, match: string): number
Finds the last occurrence index of a substring in a string
lastMatchIndex('hello world hello', 'hello') // Returns: 12snakeCase(str: string): string
Converts a string to snake_case format
snakeCase('userName') // Returns: 'user_name'
snakeCase('getUserById') // Returns: 'get_user_by_id'Object
camelCaseObject(objOrArr: JSONCandidate): JSONCandidate
Recursively converts all object keys to camelCase
camelCaseObject({ user_name: 'John', user_age: 30 })
// Returns: { userName: 'John', userAge: 30 }replaceJsonKeysRecursively<T extends JSONCandidate>(objOrArr: T, options: Partial<Omit<ReplaceJsonKeyRecursivelyOption, "keyFilter">>): T
Recursively replaces all object keys in a JSON structure using a replacer function or mapping
replaceJsonKeysRecursively({ old_key: 'value' }, { replacer: { 'old_key': 'new_key' } })
// Returns: { new_key: 'value' }reverseObjectKeyValues<T extends Record<string, string | number>>(obj: T): T | Record<string, string>
Reverses the keys and values of an object
reverseObjectKeyValues({ a: '1', b: '2' })
// Returns: { '1': 'a', '2': 'b' }snakeCaseObject(objOrArr: JSONCandidate): JSONCandidate
Recursively converts all object keys to snake_case
snakeCaseObject({ userName: 'John', userAge: 30 })
// Returns: { user_name: 'John', user_age: 30 }replaceJsonValuesRecursively<T extends JSONCandidate>(objOrArr: T, options: Partial<Omit<ReplaceJsonKeysOptions, "keyFilter">>): T
Recursively replaces values in a JSON structure based on key matching
replaceJsonValuesRecursively({ name: 'John', age: 30 }, { replacer: { age: 25 } })
// Returns: { name: 'John', age: 25 }Array
doBatch<T, R>(list: T[], work: (list: T[], batchIndex: number) => R, batchCount: number): R[]
Processes an array in batches and returns results from each batch
doBatch([1,2,3,4,5,6], (batch) => batch.reduce((sum, n) => sum + n, 0), 3)
// Processes: [1,2,3], [4,5,6] -> Returns: [6, 15]groupByArray<T, K extends string | number>(collection: T[], getKey: ((element: T) => K) | K): T[][]
Groups array elements into subarrays based on a key
groupByArray(users, user => user.age)
// Returns: [[users with age 25], [users with age 30]]groupByObject<T, K extends string | number>(collection: T[], getKey: ((element: T) => K) | K): GroupByObject<T, K>
Groups array elements into an object based on a key
groupByObject(users, user => user.age)
// Returns: { 25: [users with age 25], 30: [users with age 30] }generateArray(size: number): number[]
Generates an array of consecutive numbers from 0 to size-1
generateArray(5) // Returns: [0, 1, 2, 3, 4]lastOf<T>(arr: T[]): T
Gets the last element of an array
lastOf([1, 2, 3, 4]) // Returns: 4randomItem<T>(source: T[]): T
Selects a random element from an array
randomItem([1, 2, 3, 4, 5]) // Returns: random number between 1-5toggled<T>(arr: T[], element: T): T[]
Toggles an element in an array - adds if not present, removes if present
toggled([1, 2, 3], 4) // Returns: [1, 2, 3, 4]unique<T>(arr: T[]): T[]
Removes duplicate values from an array
unique([1, 2, 2, 3, 3, 4])
// Returns: [1, 2, 3, 4]uniqueBy<T, K>(arr: T[], getKey: (value: T) => K): T[]
Removes duplicate elements from an array by a selected key.
uniqueBy(
[
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice v2' },
],
(item) => item.id,
)
// Returns: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]Promise
withMinimumResolveTime<T>(minimumMilli: number, promise: Promise<T>): Promise<T>
Ensures a Promise takes at least a minimum amount of time to resolve
const result = await withMinimumResolveTime(1000, fetchData())
// Guarantees at least 1 second delay for UX (loading spinners)withTimeout<T>(milli: number, promise: Promise<T>): Promise<T>
Adds a timeout to a Promise, rejecting if the timeout is exceeded
const result = await withTimeout(5000, fetchUser(userId))
// Throws error if fetchUser takes more than 5 secondsType Check
is.number(candidate: any): candidate is number
Checks whether the candidate is a valid number.
is.number(42) // trueis.string(candidate: any): candidate is string
Checks whether the candidate is a string.
is.string('hello') // trueis.integerString(candidate: any): candidate is string
Checks whether the candidate is an integer string.
is.integerString('42') // trueis.numberString(candidate: any): candidate is string
Checks whether the candidate is a numeric string.
is.numberString('3.14') // trueis.null(candidate: any): candidate is null
Checks whether the candidate is null.
is.null(null) // trueis.undefined(candidate: any): candidate is undefined
Checks whether the candidate is undefined.
is.undefined(undefined) // trueis.nullOrUndefined(candidate: any): candidate is undefined | null
Checks whether the candidate is null or undefined.
is.nullOrUndefined(undefined) // trueis.falsy<T>(candidate: T | Falsy): candidate is Falsy
Checks whether the candidate is falsy.
is.falsy(0) // trueis.truthy<T>(candidate: T | Falsy): candidate is T
Checks whether the candidate is truthy.
is.truthy('hello') // trueis.function<T extends Func, R extends unknown>(candidate: T | R): candidate is T
Checks whether the candidate is a function.
is.function(() => 'hello') // trueis.object(candidate: any): candidate is Record<string, unknown>
Checks whether the candidate is a non-null object.
is.object({ value: 1 }) // trueis.plainObject(candidate: any): candidate is Record<string, unknown>
Checks whether the candidate is a plain object.
is.plainObject({ value: 1 }) // trueis.array<T>(candidate: any): candidate is Array<T>
Checks whether the candidate is an array.
is.array([1, 2, 3]) // trueis.boolean(candidate: any): candidate is boolean
Checks whether the candidate is a boolean.
is.boolean(false) // trueis.promise<T>(p: Promise<T> | any): p is Promise<T>
Checks whether the candidate is a promise.
is.promise(Promise.resolve(1)) // trueis.primitive(candidate: unknown): candidate is string | number | boolean | null | undefined
Checks whether the candidate is a primitive value.
is.primitive('hello') // trueis.notEmptyString(candidate: any): candidate is string
Checks whether the candidate is a non-empty string.
is.notEmptyString('hello') // trueis.emptyString(candidate: any): boolean
Checks whether the candidate is an empty string.
is.emptyString('') // trueis.emptyArray(candidate: any): boolean
Checks whether the candidate is an empty array.
is.emptyArray([]) // trueis.notEmptyArray<T>(candidate: any): candidate is Array<T>
Checks whether the candidate is a non-empty array.
is.notEmptyArray([1, 2, 3]) // trueFilter
filterJsonKeys(x: JSONCandidate, filter: Filter): JSONCandidate
Filters a JSON structure to include only objects/arrays containing specified keys
filterJsonKeys({ name: 'John', age: 30, city: 'NYC' }, ['name', 'age'])
// Returns: { name: 'John', age: 30 }filterNonNullish<T>(source: T[]): Exclude<T, null | undefined>[]
Filters out null and undefined values from an array
filterNonNullish([1, null, 2, undefined, 3]) // Returns: [1, 2, 3]filterNonNullishKeys<T extends object>(source: T, options?: Options): T
Filters out object keys with null, undefined, or empty string values
filterNonNullishKeys({ a: 1, b: null, c: undefined, d: 'hello' })
// Returns: { a: 1, d: 'hello' }removeValueByKeyInObject<T extends Record<string | number, any>>(v: T, key: (string | number) | (string | number)[]): T
Removes specified keys from an object and returns a new object
removeValueByKeyInObject({ a: 1, b: 2, c: 3 }, 'b') // Returns: { a: 1, c: 3 }Number
numberWithComma(x?: number): string
Adds comma separators to a number for better readability
numberWithComma(1234567) // Returns: '1,234,567'padZero(number: number | undefined, len?: number): string
Pads a number with leading zeros to reach the specified length
padZero(5) // Returns: '05'
padZero(5, 3) // Returns: '005'toFixed(number: number | undefined, fractionDigits: number, defaultString?: string): string
Safely formats a number to a specified number of decimal places
toFixed(3.14159, 2) // Returns: '3.14'
toFixed(5, 0) // Returns: '5'toFixedIfNeed(number: number | undefined, fractionDigits: number, defaultString?: string): string
Formats a number to a fixed decimal places, removing trailing zeros
toFixedIfNeed(3.1000, 4) // Returns: '3.1'
toFixedIfNeed(5.0, 2) // Returns: '5'toSiUnitString(n: number): string
Converts a number to a readable string with SI unit suffixes (K, M)
toSiUnitString(1500) // Returns: '1.5K'
toSiUnitString(2500000) // Returns: '2.5M'clamp(value: number, min: number, max: number): number
Clamps a number between a minimum and maximum value
clamp(5, 0, 10) // Returns: 5
clamp(-5, 0, 10) // Returns: 0
clamp(15, 0, 10) // Returns: 10Time
setIntervalWithTimeout(callback: (clear: () => void) => any, intervalMs: number): () => void
Creates a repeating timeout that can be cleared from within the callback
const stop = setIntervalWithTimeout((clear) => {
console.log('Running...')
if (someCondition) clear()
}, 1000)TimeoutHandler.clear(): void
Clears the current timeout and marks the handler as cleared.
const handler = new TimeoutHandler()
handler.clear()parseSecond(totalSecond?: number): Result
Parses total seconds into structured time components
parseSecond(3661) // Returns: { totalDay: 0, totalHour: 1, totalMinute: 61, onlyHour: 1, onlyMinute: 1, onlySecond: 1 }SecFormat.get(type: SecFormats): Formatter
Returns the formatter for the given second format.
const formatter = SecFormat.get('mm:ss')
formatter(90) // Returns: '01:30'SecFormat.format(totalSeconds: number, type: SecFormats): string
Formats total seconds with the given second format.
SecFormat.format(3661, 'hh:mm:ss') // Returns: '01:01:01'SecFormat.invalidateIntervalSec(type: SecFormats): number
Returns the cache invalidation interval for the given second format.
SecFormat.invalidateIntervalSec('mm:ss') // Returns: 1formatSec(totalSeconds: number, type: SecFormats): string
Alias for SecFormat.format - formats seconds into time string
formatSec(3661, 'hh:mm:ss') // Returns: '01:01:01'
formatSec(90, 'mm:ss') // Returns: '01:30'createTimer(): { clear: () => void; timeout: (fn: () => void, duration: number, { clear: clearOtherTimers }?: Options) => () => void; }
Creates a timer utility that manages multiple timeouts with optional clearing
const timer = createTimer()
timer.timeout(() => console.log('Hello'), 1000)
timer.clear() // Clears all timeoutscreateTimer().clear(): void
Clears every timeout created by this timer instance.
const timer = createTimer()
timer.clear()createTimer().timeout(fn: () => void, duration: number, { clear: clearOtherTimers }?: Options): () => void
Schedules a timeout and optionally clears earlier timeouts first.
const timer = createTimer()
timer.timeout(() => console.log('Hello'), 1000)Math
interpolate({ value, inputRange, outputRange, extrapolate, }: { value: number; inputRange: [number, number]; outputRange: [number, number]; extrapolate?: "clamp" | "extend"; }): number
Maps a value from one range to another range with optional extrapolation control
interpolate({ value: 50, inputRange: [0, 100], outputRange: [0, 1] }) // Returns: 0.5
interpolate({ value: 150, inputRange: [0, 100], outputRange: [0, 1], extrapolate: 'clamp' }) // Returns: 1
interpolate({ value: 25, inputRange: [0, 100], outputRange: [100, 0] }) // Returns: 75interpolateColor({ value, inputRange, outputRange, }: { value: number; inputRange: [number, number]; outputRange: [string, string]; }): string
Interpolates between two hex colors based on a value within an input range
interpolateColor({ value: 50, inputRange: [0, 100], outputRange: ['#ff0000', '#00ff00'] }) // Returns: '#808000'
interpolateColor({ value: 0, inputRange: [0, 100], outputRange: ['#000000', '#ffffff'] }) // Returns: '#000000'
interpolateColor({ value: 100, inputRange: [0, 100], outputRange: ['#000000', '#ffffff'] }) // Returns: '#ffffff'Misc
formatJson(a: any): string
Converts a value to a formatted JSON string representation
formatJson({ name: 'John', age: 30 }) // Returns: '{\n "name": "John",\n "age": 30\n}'TypeScript Support
All functions include comprehensive TypeScript type definitions and JSDoc documentation for excellent IDE support.
Contributing
See CONTRIBUTING.md for contribution guidelines.
License
MIT © MJ Studio
