hearty-helper
v2.1.0
Published
A comprehensive TypeScript utility library — numbers, strings, arrays, objects, validators, and more. Your single source of utility functions.
Downloads
57
Maintainers
Readme
hearty-helper
A comprehensive TypeScript utility library -- numbers, strings, arrays, objects, validators, and more. Your single source of utility functions.
Note: Date/time utilities live in the separate
hearty-datetime-helperpackage.
Installation
npm install hearty-helperQuick Start
// ESM
import { formatCurrency, chunk, deepMerge, isEmail } from 'hearty-helper'
// CommonJS
const { formatCurrency, chunk, deepMerge, isEmail } = require('hearty-helper')API Reference
Number Formatters
formatCurrency(num, currency?, locale?)
Formats a number as a currency string using Intl.NumberFormat.
formatCurrency(1234.56) // "$1,234.56"
formatCurrency(1234.56, "EUR", "de-DE") // "1.234,56 €"formatCompact(num)
Formats a number in compact notation.
formatCompact(1000) // "1K"
formatCompact(1500000) // "1.5M"
formatCompact(1000000000) // "1B"clamp(num, min, max)
Clamps a number between min and max.
clamp(15, 0, 10) // 10
clamp(-5, 0, 10) // 0roundTo(num, decimals)
Rounds to N decimal places.
roundTo(3.14159, 2) // 3.14toOrdinal(num)
Converts to ordinal string.
toOrdinal(1) // "1st"
toOrdinal(2) // "2nd"
toOrdinal(11) // "11th"
toOrdinal(23) // "23rd"isEven(num) / isOdd(num)
Check if a number is even or odd.
percentage(value, total)
Calculate percentage.
percentage(25, 200) // 12.5sum(numbers[]) / average(numbers[])
Sum or average an array of numbers.
sum([1, 2, 3, 4]) // 10
average([1, 2, 3, 4]) // 2.5padNumber(num, length)
Pad with leading zeros.
padNumber(5, 3) // "005"
padNumber(42, 5) // "00042"toFixedNumber(num, decimals)
Like toFixed but returns a number.
toFixedNumber(1.2345, 2) // 1.23inRange(num, start, end)
Check if number is within range (inclusive).
inRange(5, 1, 10) // trueformatBytes(bytes, decimals?)
Format bytes into human-readable string.
formatBytes(1024) // "1 KB"
formatBytes(1048576) // "1 MB"randomInt(min, max)
Random integer between min and max (inclusive).
randomInt(1, 10) // e.g. 7Regex Validators
isEmail(str)
isEmail("[email protected]") // true
isEmail("invalid") // falseisURL(str)
isURL("https://example.com") // true
isURL("not-a-url") // falseisIPv4(str) / isIPv6(str)
isIPv4("192.168.1.1") // true
isIPv6("::1") // false (simplified; full form required)isHexColor(str)
isHexColor("#fff") // true
isHexColor("#ffffff") // true
isHexColor("#ggg") // falseisCreditCard(str)
Validates using the Luhn algorithm.
isCreditCard("4532015112830366") // trueisStrongPassword(str)
Min 8 chars, uppercase, lowercase, number, special char.
isStrongPassword("Abcdef1!") // true
isStrongPassword("weak") // falseisUUID(str)
isUUID("550e8400-e29b-41d4-a716-446655440000") // trueisSlug(str)
isSlug("hello-world") // true
isSlug("Hello World") // falseisMACAddress(str)
isMACAddress("00:1A:2B:3C:4D:5E") // trueisLatLong(str)
isLatLong("40.7128,-74.0060") // trueisPostalCode(str, locale?)
Supports US (default), UK, CA, DE, FR, IN, JP, AU.
isPostalCode("12345") // true (US)
isPostalCode("SW1A 1AA", "UK") // true
isPostalCode("500001", "IN") // trueisPhoneNumber(str)
Basic international phone number validation.
isPhoneNumber("+14155552671") // trueString Utilities
isAlphanumeric(str)
isAlphanumeric("abc123") // true
isAlphanumeric("abc@123") // falseremoveSpaces(str)
Removes all whitespace.
removeSpaces("hello world") // "helloworld"getRandomString(length?)
Random alphanumeric string (default length: 10).
getRandomString(8) // e.g. "aB3xK9mQ"getTimestamp()
Current Unix timestamp in milliseconds.
capitalize(str)
capitalize("hello") // "Hello"capitalizeWords(str)
capitalizeWords("hello world") // "Hello World"camelCase(str) / snakeCase(str) / kebabCase(str) / pascalCase(str)
camelCase("hello world") // "helloWorld"
snakeCase("helloWorld") // "hello_world"
kebabCase("helloWorld") // "hello-world"
pascalCase("hello world") // "HelloWorld"truncate(str, length, suffix?)
truncate("Hello World", 8) // "Hello..."slugify(str)
slugify("Hello World!") // "hello-world"escapeHtml(str) / unescapeHtml(str)
escapeHtml('<script>alert("xss")</script>')
// "<script>alert("xss")</script>"reverseString(str)
reverseString("hello") // "olleh"countOccurrences(str, substr)
countOccurrences("hello world hello", "hello") // 2isPalindrome(str)
isPalindrome("racecar") // truemask(str, visibleCount?, maskChar?)
mask("1234567890") // "******7890"
mask("1234567890", 2) // "********90"wordCount(str)
wordCount("hello world") // 2stripHtml(str)
stripHtml("<p>Hello <b>World</b></p>") // "Hello World"initials(str)
initials("John Doe") // "JD"URL Utilities
getUrlParams(url?)
Parses URL query parameters into an object.
getUrlParams("https://example.com?name=sri&page=2")
// { name: "sri", page: "2" }parseQueryString(str)
parseQueryString("?name=sri&page=2") // { name: "sri", page: "2" }buildQueryString(obj)
buildQueryString({ name: "sri", page: 2 }) // "name=sri&page=2"Object Utilities
isObject(data)
isObject({ a: 1 }) // true
isObject([]) // false
isObject(null) // falsegetSizeOfObject(data)
getSizeOfObject({ a: 1, b: 2 }) // 2
getSizeOfObject([]) // nullisObjectEmpty(data)
isObjectEmpty({}) // true
isObjectEmpty({ a: 1 }) // falsedeepClone(obj)
Deep clone using structuredClone.
const clone = deepClone({ a: { b: 1 } })pick(obj, keys[])
pick({ a: 1, b: 2, c: 3 }, ["a", "c"]) // { a: 1, c: 3 }omit(obj, keys[])
omit({ a: 1, b: 2, c: 3 }, ["b"]) // { a: 1, c: 3 }deepMerge(target, ...sources)
deepMerge({ a: { b: 1 } }, { a: { c: 2 } })
// { a: { b: 1, c: 2 } }flattenObject(obj, separator?)
flattenObject({ a: { b: { c: 1 } } }) // { "a.b.c": 1 }unflattenObject(obj, separator?)
unflattenObject({ "a.b.c": 1 }) // { a: { b: { c: 1 } } }invertObject(obj)
invertObject({ a: "1", b: "2" }) // { "1": "a", "2": "b" }mapKeys(obj, fn) / mapValues(obj, fn)
mapKeys({ a: 1 }, k => k.toUpperCase()) // { A: 1 }
mapValues({ a: 1 }, v => v * 10) // { a: 10 }hasPath(obj, path)
hasPath({ a: { b: { c: 1 } } }, "a.b.c") // true
hasPath({ a: 1 }, "a.b.c") // falsegetPath(obj, path, defaultValue?)
getPath({ a: { b: 42 } }, "a.b") // 42
getPath({ a: 1 }, "a.b.c", "default") // "default"setPath(obj, path, value)
Returns a new object with the value set at the path.
setPath({ a: { b: 1 } }, "a.c", 2) // { a: { b: 1, c: 2 } }Array Utilities
unique(arr)
unique([1, 2, 2, 3]) // [1, 2, 3]uniqueBy(arr, key)
uniqueBy([{ id: 1 }, { id: 2 }, { id: 1 }], "id")
// [{ id: 1 }, { id: 2 }]chunk(arr, size)
chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]flatten(arr, depth?)
flatten([[1, 2], [3, [4]]]) // [1, 2, 3, [4]]
flatten([[1, 2], [3, [4]]], 2) // [1, 2, 3, 4]shuffle(arr)
Fisher-Yates shuffle. Returns a new array.
groupBy(arr, key)
groupBy([{ type: "a" }, { type: "b" }, { type: "a" }], "type")
// { a: [...], b: [...] }sortBy(arr, key, order?)
sortBy([{ n: 3 }, { n: 1 }], "n") // [{ n: 1 }, { n: 3 }]
sortBy([{ n: 3 }, { n: 1 }], "n", "desc") // [{ n: 3 }, { n: 1 }]intersection(arr1, arr2) / difference(arr1, arr2) / union(arr1, arr2)
intersection([1, 2, 3], [2, 3, 4]) // [2, 3]
difference([1, 2, 3], [2, 3, 4]) // [1]
union([1, 2], [2, 3]) // [1, 2, 3]compact(arr)
compact([0, 1, false, 2, "", null]) // [1, 2]sample(arr)
Returns a random element.
range(start, end, step?)
range(0, 5) // [0, 1, 2, 3, 4]
range(0, 10, 3) // [0, 3, 6, 9]partition(arr, predicate)
partition([1, 2, 3, 4], n => n % 2 === 0) // [[2, 4], [1, 3]]zip(...arrays) / unzip(arr)
zip([1, 2], ["a", "b"]) // [[1, "a"], [2, "b"]]
unzip([[1, "a"], [2, "b"]]) // [[1, 2], ["a", "b"]]first(arr, n?) / last(arr, n?)
first([1, 2, 3]) // 1
first([1, 2, 3], 2) // [1, 2]
last([1, 2, 3]) // 3
last([1, 2, 3], 2) // [2, 3]countBy(arr, key)
countBy(["apple", "banana", "avocado"], s => s[0])
// { a: 2, b: 1 }minBy(arr, key) / maxBy(arr, key)
minBy([{ n: 3 }, { n: 1 }, { n: 2 }], "n") // { n: 1 }
maxBy([{ n: 3 }, { n: 1 }, { n: 2 }], "n") // { n: 3 }JSON Utilities
isJson(str)
isJson('{"name":"sri"}') // true
isJson('not json') // falseMisc Utilities
debounce(fn, delay)
Creates a debounced function.
const search = debounce(query => fetchResults(query), 300)throttle(fn, delay)
Creates a throttled function.
const onScroll = throttle(handleScroll, 100)sleep(ms)
Promise-based delay.
await sleep(1000)retry(fn, retries?, delay?)
Retry an async function.
const data = await retry(() => fetchData(), 3, 1000)memoize(fn)
Basic memoization.
const cached = memoize(expensiveFunction)pipe(...fns) / compose(...fns)
const transform = pipe(
(x: number) => x + 1,
(x: number) => x * 2,
)
transform(3) // 8
const transform2 = compose(
(x: number) => x + 1,
(x: number) => x * 2,
)
transform2(3) // 7deepEqual(a, b)
Deep equality check.
deepEqual({ a: { b: 1 } }, { a: { b: 1 } }) // truegenerateId(length?)
URL-safe unique ID (default 21 chars).
generateId() // e.g. "V1StGXR8_Z5jdHi6B-myT"
generateId(10) // e.g. "aBc1D_e2Fg"noop()
A no-op function that does nothing.
times(n, fn)
times(3, i => i * 2) // [0, 2, 4]isEmpty(value)
Checks if a value is empty (string, array, object, null, undefined).
isEmpty("") // true
isEmpty([]) // true
isEmpty({}) // true
isEmpty(null) // true
isEmpty("hello") // falseSession Utilities (Browser only)
getSessionId(sessionKey)
Gets or creates a session ID in sessionStorage.
Cookie Utilities (Browser only)
setCookie(options) / getCookie(name)
setCookie({ cname: 'theme', cvalue: 'dark', expires: 7 })
getCookie('theme') // 'dark'HTTP Utilities
sendHttpRequest<T>(url, options?)
const data = await sendHttpRequest('https://api.example.com/users')Tech Stack
| Tool | Purpose | |------|---------| | TypeScript | Type-safe source code | | tsup | Bundling (ESM + CJS dual output) | | Vitest | Testing | | Node.js 18+ | Minimum runtime |
Development
npm install
npm test
npm run test:watch
npm run build
npm run lintMigration from v1
v2 is a major rewrite in TypeScript with modern tooling. Key changes:
- ESM + CJS dual exports -- works with both
importandrequire - TypeScript types included -- full type definitions shipped with the package
sendHttpRequestnow uses Fetch API -- returns a Promise instead of using callbackssetCookieno longer hardcodes a domain -- you must providedomainexplicitlygetRandomNumberrenamed togetTimestamp-- old name still works as a deprecated aliasgeturlParamsrenamed togetUrlParams-- old name still works as a deprecated alias
Author
Srinivas N -- [email protected]
