npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@nadershak/utils

v1.0.1

Published

Reusable, tree-shakable utilities for any front-end project

Downloads

180

Readme

@nadershak/utils

A comprehensive, tree-shakable TypeScript utility library for front-end projects. Works with React, Vue, Angular, Svelte, or Vanilla JS.

Features

  • 🌳 Tree-shakable - Import only what you need
  • 📦 TypeScript - Full type safety and IntelliSense support
  • 🧪 Well-tested - Comprehensive unit tests with Vitest
  • 🚀 Modern - ES modules and CommonJS support
  • 📚 Well-documented - JSDoc comments for all utilities

Installation

npm install @nadershak/utils
# or
yarn add @nadershak/utils
# or
pnpm add @nadershak/utils

Usage

Import individual utilities

import { capitalize, debounce, formatDate } from '@nadershak/utils';

const text = capitalize('hello world'); // 'Hello world'
const debouncedFn = debounce(() => console.log('Hello'), 300);
const formatted = formatDate(new Date()); // '1/15/2023'

Import React hooks

import { useLocalStorage } from '@nadershak/utils/react';

function MyComponent() {
  const [user, setUser] = useLocalStorage('user', { name: 'Guest' });
  
  // ...
}

API Reference

String Utilities

capitalize(str: string): string

Capitalizes the first letter of a string.

capitalize('hello') // 'Hello'
capitalize('HELLO') // 'Hello'

camelCase(str: string): string

Converts a string to camelCase.

camelCase('hello world') // 'helloWorld'
camelCase('hello-world') // 'helloWorld'

kebabCase(str: string): string

Converts a string to kebab-case.

kebabCase('hello world') // 'hello-world'
kebabCase('HelloWorld') // 'hello-world'

truncate(str: string, length: number, suffix?: string): string

Truncates a string to a specified length.

truncate('Hello world', 5) // 'Hello...'
truncate('Hello world', 5, '') // 'Hello'

stripHTML(str: string): string

Removes HTML tags from a string.

stripHTML('<p>Hello <b>world</b></p>') // 'Hello world'

randomString(length?: number, chars?: string): string

Generates a random string.

randomString(8) // 'aB3dEf9h'
randomString(8, '0123456789') // '12345678'

normalizeString(str: string): string

Normalizes a string by removing diacritics.

normalizeString('Café') // 'cafe'
normalizeString('Müller') // 'muller'

isEmail(str: string): boolean

Validates if a string is a valid email address.

isEmail('[email protected]') // true
isEmail('invalid-email') // false

isPhone(str: string): boolean

Validates if a string is a valid phone number.

isPhone('+1234567890') // true
isPhone('(123) 456-7890') // true

Number Utilities

clamp(value: number, min: number, max: number): number

Clamps a number between min and max.

clamp(15, 0, 10) // 10
clamp(-5, 0, 10) // 0
clamp(5, 0, 10) // 5

randomInt(min?: number, max?: number): number

Generates a random integer.

randomInt(1, 10) // Random number between 1 and 10

isNumeric(value: unknown): boolean

Checks if a value is numeric.

isNumeric(123) // true
isNumeric('123') // true
isNumeric('abc') // false

roundTo(value: number, decimals?: number): number

Rounds a number to specified decimal places.

roundTo(3.14159, 2) // 3.14
roundTo(3.14159, 0) // 3

percentage(value: number, total: number, decimals?: number): number

Calculates percentage.

percentage(25, 100) // 25
percentage(1, 3) // 33.33

formatNumber(value: number, locale?: string, options?: Intl.NumberFormatOptions): string

Formats a number with thousand separators.

formatNumber(1234567.89) // '1,234,567.89'
formatNumber(1234567.89, 'de-DE') // '1.234.567,89'

Date Utilities

formatDate(date: Date | string | number, format?: string | Intl.DateTimeFormatOptions, options?: Intl.DateTimeFormatOptions): string

Formats a date. Supports custom separators, locale strings, or Intl.DateTimeFormatOptions.

formatDate(new Date('2023-01-15')) // '1/15/2023'
formatDate(new Date('2023-01-15'), '-') // '1-15-2023'
formatDate(new Date('2023-01-15'), 'en-GB') // '15/01/2023'
formatDate(new Date('2023-01-15'), 'en-US', { dateStyle: 'full' }) // 'Sunday, January 15, 2023'

timeAgo(date: Date | string | number, now?: Date): string

Returns a human-readable time ago string.

timeAgo(new Date(Date.now() - 3600000)) // '1 hour ago'
timeAgo(new Date(Date.now() - 86400000)) // '1 day ago'

isValidDate(value: unknown): value is Date

Checks if a value is a valid Date object.

isValidDate(new Date()) // true
isValidDate(new Date('invalid')) // false

addDays(date: Date | string | number, days: number): Date

Adds days to a date.

addDays(new Date('2023-01-15'), 5) // Date object for 2023-01-20

subtractDays(date: Date | string | number, days: number): Date

Subtracts days from a date.

subtractDays(new Date('2023-01-15'), 5) // Date object for 2023-01-10

compareDates(date1: Date | string | number, date2: Date | string | number): number

Compares two dates.

compareDates(new Date('2023-01-15'), new Date('2023-01-20')) // -1
compareDates(new Date('2023-01-15'), new Date('2023-01-15')) // 0

getDayName(date: Date | string | number, locale?: string, format?: 'long' | 'short' | 'narrow'): string

Gets the day name.

getDayName(new Date('2023-01-15')) // 'Sunday'
getDayName(new Date('2023-01-15'), 'en-US', 'short') // 'Sun'

getMonthName(date: Date | string | number, locale?: string, format?: 'long' | 'short' | 'narrow'): string

Gets the month name.

getMonthName(new Date('2023-01-15')) // 'January'
getMonthName(new Date('2023-01-15'), 'en-US', 'short') // 'Jan'

Array Utilities

unique<T>(arr: T[]): T[]

Returns unique values from an array.

unique([1, 2, 2, 3, 3, 3]) // [1, 2, 3]

chunk<T>(arr: T[], size: number): T[][]

Splits an array into chunks.

chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]

flatten<T>(arr: (T | T[])[], depth?: number): T[]

Flattens a nested array.

flatten([1, [2, 3], [4, [5]]]) // [1, 2, 3, 4, [5]]
flatten([1, [2, 3], [4, [5]]], 2) // [1, 2, 3, 4, 5]

shuffle<T>(arr: T[]): T[]

Shuffles an array.

shuffle([1, 2, 3, 4, 5]) // [3, 1, 5, 2, 4] (random order)

sortByKey<T>(arr: T[], key: keyof T, direction?: 'asc' | 'desc'): T[]

Sorts an array of objects by a key.

sortByKey([{ name: 'Bob', age: 30 }, { name: 'Alice', age: 25 }], 'age')
// [{ name: 'Alice', age: 25 }, { name: 'Bob', age: 30 }]

removeItem<T>(arr: T[], item: T): T[]

Removes an item from an array.

removeItem([1, 2, 3, 2], 2) // [1, 3]

groupBy<T>(arr: T[], key: keyof T | ((item: T) => string | number)): Record<string, T[]>

Groups an array by a key.

groupBy([{ type: 'fruit', name: 'apple' }, { type: 'fruit', name: 'banana' }, { type: 'veg', name: 'carrot' }], 'type')
// { fruit: [...], veg: [...] }

Object Utilities

deepClone<T>(obj: T): T

Creates a deep clone of an object.

const obj = { a: 1, b: { c: 2 } };
const cloned = deepClone(obj);
cloned.b.c = 3;
// obj.b.c is still 2

deepMerge<T>(target: T, ...sources: Partial<T>[]): T

Deeply merges objects.

deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 }, e: 4 })
// { a: 1, b: { c: 2, d: 3 }, e: 4 }

isEmptyObject(obj: unknown): boolean

Checks if an object is empty.

isEmptyObject({}) // true
isEmptyObject({ a: 1 }) // false

omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>

Creates an object with omitted properties.

omit({ a: 1, b: 2, c: 3 }, ['a', 'c']) // { b: 2 }

pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>

Creates an object with only specified properties.

pick({ a: 1, b: 2, c: 3 }, ['a', 'c']) // { a: 1, c: 3 }

getNestedValue<T>(obj: Record<string, unknown>, path: string, defaultValue?: T): T | undefined

Gets a nested value from an object.

getNestedValue({ user: { profile: { name: 'John' } } }, 'user.profile.name') // 'John'
getNestedValue({ user: { profile: { name: 'John' } } }, 'user.profile.age', 0) // 0

Validation Utilities

isEmail(str: string): boolean

Validates email address.

isEmail('[email protected]') // true

isURL(str: string): boolean

Validates URL.

isURL('https://example.com') // true

isPhoneNumber(str: string): boolean

Validates phone number.

isPhoneNumber('+1234567890') // true

isStrongPassword(str: string): boolean

Validates strong password.

isStrongPassword('MyP@ssw0rd') // true

isJSON(str: string): boolean

Validates JSON string.

isJSON('{"key": "value"}') // true

isUUID(str: string): boolean

Validates UUID.

isUUID('550e8400-e29b-41d4-a716-446655440000') // true

isEmpty(value: unknown): boolean

Checks if a value is empty.

isEmpty('') // true
isEmpty([]) // true
isEmpty({}) // true
isEmpty(null) // true

DOM Utilities

addClass(element: Element | string, className: string): void

Adds a CSS class to an element.

addClass('#myElement', 'active')
addClass(document.querySelector('.item'), 'highlighted')

removeClass(element: Element | string, className: string): void

Removes a CSS class from an element.

removeClass('#myElement', 'active')

toggleClass(element: Element | string, className: string): boolean

Toggles a CSS class on an element.

toggleClass('#myElement', 'active')

scrollToTop(behavior?: ScrollBehavior): void

Scrolls to the top.

scrollToTop() // smooth scroll
scrollToTop('auto') // instant scroll

scrollToBottom(behavior?: ScrollBehavior): void

Scrolls to the bottom.

scrollToBottom()

isInViewport(element: Element | string, partial?: boolean): boolean

Checks if an element is in the viewport.

isInViewport('#myElement') // true if visible
isInViewport('#myElement', true) // true if partially visible

getOffset(element: Element | string): { top: number; left: number }

Gets the offset position of an element.

getOffset('#myElement') // { top: 100, left: 50 }

Storage Utilities

setLocal<T>(key: string, value: T): void

Sets a value in localStorage.

setLocal('user', { name: 'John', age: 30 })
setLocal('theme', 'dark')

getLocal<T>(key: string, defaultValue?: T): T | undefined

Gets a value from localStorage.

const user = getLocal('user', { name: 'Guest' })
const theme = getLocal('theme', 'light')

removeLocal(key: string): void

Removes a value from localStorage.

removeLocal('user')

setSession<T>(key: string, value: T): void

Sets a value in sessionStorage.

setSession('tempData', { id: 123 })

getSession<T>(key: string, defaultValue?: T): T | undefined

Gets a value from sessionStorage.

const tempData = getSession('tempData', {})

removeSession(key: string): void

Removes a value from sessionStorage.

removeSession('tempData')

copyToClipboard(text: string): Promise<void>

Copies text to clipboard.

await copyToClipboard('Hello World')

downloadFile(content: string | Blob, filename: string, mimeType?: string): void

Downloads a file.

downloadFile('Hello World', 'hello.txt')
downloadFile(new Blob(['data']), 'data.bin', 'application/octet-stream')

Async Utilities

sleep(ms: number): Promise<void>

Creates a promise that resolves after a delay.

await sleep(1000) // waits 1 second

retry<T>(fn: () => Promise<T>, retries?: number, delay?: number): Promise<T>

Retries an async function.

const result = await retry(() => fetchData(), 3, 1000)

debouncePromise<T>(fn: T, delay: number): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>>

Debounces a promise-returning function.

const debouncedFetch = debouncePromise(fetchData, 300)
await debouncedFetch() // only the last call will resolve

timeoutPromise<T>(promise: Promise<T>, timeout: number, errorMessage?: string): Promise<T>

Wraps a promise with a timeout.

const result = await timeoutPromise(fetchData(), 5000, 'Request timed out')

Performance Utilities

debounce<T>(fn: T, delay: number): (...args: Parameters<T>) => void

Debounces a function.

const debouncedSearch = debounce((query) => search(query), 300)
debouncedSearch('hello') // will only execute after 300ms of no calls

throttle<T>(fn: T, delay: number): (...args: Parameters<T>) => void

Throttles a function.

const throttledScroll = throttle(() => handleScroll(), 100)
throttledScroll() // will execute at most once per 100ms

memoize<T>(fn: T, keyFn?: (...args: Parameters<T>) => string): (...args: Parameters<T>) => ReturnType<T>

Memoizes a function.

const memoizedExpensive = memoize((n) => expensiveCalculation(n))
memoizedExpensive(5) // calculates and caches
memoizedExpensive(5) // returns cached result

Network Utilities

fetchJSON<T>(url: string, options?: RequestInit): Promise<T>

Fetches JSON data.

const data = await fetchJSON('/api/users')
const user = await fetchJSON('/api/user/1', { method: 'POST', body: JSON.stringify({ name: 'John' }) })

fetchWithTimeout(url: string, timeout?: number, options?: RequestInit): Promise<Response>

Fetches with timeout.

const response = await fetchWithTimeout('/api/data', 3000)

parseQueryString(queryString?: string): Record<string, string>

Parses a query string.

parseQueryString('?name=John&age=30') // { name: 'John', age: '30' }
parseQueryString() // parses window.location.search

createQueryString(params: Record<string, string | number | boolean>): string

Creates a query string.

createQueryString({ name: 'John', age: 30 }) // '?name=John&age=30'

React Hooks

useThrottle<T>(value: T, delay?: number): T

Throttles a value.

const [scrollY, setScrollY] = useState(0);
const throttledScroll = useThrottle(scrollY, 100);

useLocalStorage<T>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void]

Manages localStorage with React state.

const [user, setUser] = useLocalStorage('user', { name: 'Guest' });
setUser({ name: 'John' }); // updates both state and localStorage

useSessionStorage<T>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void]

Manages sessionStorage with React state.

const [viewMode, setViewMode] = useSessionStorage('viewMode', 'list');

usePrevious<T>(value: T): T | undefined

Returns the previous value.

const [count, setCount] = useState(0);
const prevCount = usePrevious(count);

useBoolean(initialValue?: boolean)

Manages boolean state with convenient helpers.

const { value, toggle, setTrue, setFalse } = useBoolean(false);
toggle(); // toggles the value
setTrue(); // sets to true
setFalse(); // sets to false

useUpdateEffect(effect: () => void | (() => void), deps: unknown[]): void

Runs an effect only on updates.

useUpdateEffect(() => {
  console.log('Component updated');
}, [someValue]);

Security Utilities

sanitizeInput(input: string): string

Sanitizes user input by escaping HTML.

sanitizeInput('<script>alert("xss")</script>') // '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'

hashString(str: string, algorithm?: string): Promise<string>

Hashes a string using Web Crypto API.

const hash = await hashString('password123')

secureCompare(a: string, b: string): boolean

Performs constant-time string comparison.

secureCompare('secret', 'secret') // true
secureCompare('secret', 'wrong') // false

Misc Utilities

uuid(): string

Generates a UUID v4.

uuid() // '550e8400-e29b-41d4-a716-446655440000'

generateId(prefix?: string, length?: number): string

Generates a unique ID.

generateId() // 'a1b2c3d4'
generateId('user', 12) // 'user_a1b2c3d4e5f6'

isClient(): boolean

Checks if running in browser.

if (isClient()) {
  // browser-only code
}

isServer(): boolean

Checks if running on server.

if (isServer()) {
  // server-only code
}

Types

DeepPartial<T>

Makes all properties deeply partial.

type User = { name: string; address: { city: string } };
type PartialUser = DeepPartial<User>; // { name?: string; address?: { city?: string } }

Nullable<T>

Makes T nullable.

type MaybeString = Nullable<string>; // string | null

Optional<T>

Makes T optional.

type MaybeString = Optional<string>; // string | undefined

ValueOf<T>

Extracts value type from object.

type User = { name: string; age: number };
type UserValue = ValueOf<User>; // string | number

Tree Shaking

This package is fully tree-shakable. Import only what you need:

// ✅ Good - only imports what you use
import { capitalize, debounce } from '@nadershak/utils';

// ❌ Avoid - imports everything
import * as utils from '@nadershak/utils';

Development

# Install dependencies
npm install

# Run tests
npm test

# Build
npm run build

# Type check
npm run typecheck

License

MIT