JavaScript Micro-Utilities
Zero-dependency utilities for common JavaScript operations. Prefer native APIs (in backticks) over packages. Install
just-*
packages only when native solutions don't exist.
Installation
npm i just-diff just-compare just-extend just-pick just-omit # objects
npm i just-shuffle just-partition just-range just-order-by # arrays
npm i just-debounce-it just-throttle just-memoize just-once # functions
Import with ESM:
import diff from 'just-diff';
import shuffle from 'just-shuffle';
Collections {}[]
| Need | Solution |
|---|
| Deep diff two objects/arrays | just-diff
|
| Apply JSON-patch to object | just-diff-apply
|
| Deep equality check | just-compare
|
| Deep clone | structuredClone(obj)
|
| Extract property from array | arr.map(x => x.prop)
|
| Remove nullish from array | arr.filter(x => x != null)
|
Objects {}
Merging
| Need | Solution |
|---|
| Deep merge | just-extend
|
| Shallow merge | {...a, ...b} or Object.assign(target, src)
|
Extracting
| Need | Solution |
|---|
| Values as array | Object.values(obj)
|
| Key-value pairs | Object.entries(obj)
|
| Keep only certain keys | just-pick
|
| Exclude certain keys | just-omit
|
Transforming
// Filter properties
Object.fromEntries(Object.entries(obj).filter(([k, v]) => predicate(k, v)))
// Map values
Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)]))
// Map keys
Object.fromEntries(Object.entries(obj).map(([k, v]) => [fn(k), v]))
// Swap keys/values
Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k]))
// Reduce to value
Object.entries(obj).reduce((acc, [k, v]) => ..., init)
Deep Operations
| Need | Solution |
|---|
| Map values recursively | just-deep-map-values
|
| Safe nested get | obj?.a?.b?.c
|
| Safe nested set | just-safe-set
|
| Check nested exists | obj?.a?.b !== undefined
|
Type Checking
| Need | Solution |
|---|
| Is empty | just-is-empty
|
| Has circular refs | just-is-circular
|
| Is primitive | typeof x !== 'object' || x === null
|
| Better typeof | just-typeof (distinguishes array, null, date, regexp) |
Arrays []
Access
| Need | Solution |
|---|
| Last element | arr.at(-1)
|
| All except first | arr.slice(1)
|
| Random element | just-random
|
Creating
| Need | Solution |
|---|
| Number sequence | just-range
|
| All combinations | just-cartesian-product
|
| All orderings | just-permutations
|
Transforming
| Need | Solution |
|---|
| Dedupe primitives | [...new Set(arr)]
|
| Flatten nested | arr.flat(depth)
|
| Remove falsy | arr.filter(Boolean)
|
| Shuffle | just-shuffle
|
| Chunk into groups | just-split
|
Sorting
| Need | Solution |
|---|
| Immutable sort by prop | arr.toSorted((a, b) => a.prop - b.prop)
|
| Multi-prop sort | just-order-by
|
Set Operations
| Need | Solution |
|---|
| Intersection | arr1.filter(x => arr2.includes(x))
|
| Difference | arr.filter(x => !remove.includes(x))
|
| Union (deduped) | [...new Set([...a, ...b])]
|
Splitting
// Split at index
[arr.slice(0, i), arr.slice(i)]
// Split by predicate → [matches, nonMatches]
import partition from 'just-partition';
const [evens, odds] = partition(arr, x => x % 2 === 0);
Grouping
// Native grouping (ES2024)
Object.groupBy(arr, item => item.category)
// Array to object by key
Object.fromEntries(arr.map(x => [x[key], x]))
// Zip arrays together
import zip from 'just-zip-it';
zip([1, 2], ['a', 'b']) // [[1, 'a'], [2, 'b']]
Inserting
// Insert at index (immutable)
arr.toSpliced(i, 0, ...items)
Statistics Σ
| Need | Solution |
|---|
| Average | arr.reduce((a, b) => a + b, 0) / arr.length
|
| Median | just-median
|
| Mode | just-mode
|
| Percentile | just-percentile
|
| Variance | just-variance
|
| Std deviation | just-standard-deviation
|
| Skewness | just-skewness
|
Strings ""
Padding & Truncation
| Need | Solution |
|---|
| Pad start | str.padStart(n, char)
|
| Pad end | str.padEnd(n, char)
|
Truncate with ...
| just-truncate
|
| Truncate at word | just-prune
|
Case Conversion
| Need | Solution |
|---|
| camelCase | just-camel-case
|
| kebab-case | just-kebab-case
|
| snake_case | just-snake-case
|
| PascalCase | just-pascal-case
|
| Capitalize first | str[0].toUpperCase() + str.slice(1)
|
Replacement
| Need | Solution |
|---|
| Replace all | str.replaceAll(find, replace)
|
| Remove whitespace | str.replaceAll(' ', '')
|
| Template interpolation | just-template (supports {{a.b.c}} paths) |
Numbers +-
| Need | Solution |
|---|
| Clamp to range | Math.min(Math.max(n, min), max)
|
| Is prime | just-is-prime
|
| True modulo (neg-safe) | just-modulo
|
| Random int in range | Math.floor(Math.random() * (max - min + 1)) + min
|
Functions =>
Composition
| Need | Solution |
|---|
Right-to-left f(g(h(x)))
| just-compose
|
Left-to-right h(g(f(x)))
| just-pipe
|
Partial Application
| Need | Solution |
|---|
| Curry | just-curry-it
|
| Fix args with placeholders | just-partial-it
|
| Swap first two args | just-flip
|
| Method to function | Function.prototype.call.bind(method)
|
Rate Limiting
| Need | Solution |
|---|
| Debounce (wait for pause) | just-debounce-it
|
| Throttle (once per interval) | just-throttle
|
| Run only first call | just-once
|
Caching
| Need | Solution |
|---|
| Memoize by args | just-memoize
|
| Cache last call only | just-memoize-last
|
Quick Reference
Most Common Native
// Clone
const copy = structuredClone(obj);
// Dedupe
const unique = [...new Set(arr)];
// Last element
const last = arr.at(-1);
// Safe access
const val = obj?.deeply?.nested?.prop;
// Group by
const grouped = Object.groupBy(items, x => x.type);
// Immutable sort
const sorted = arr.toSorted((a, b) => a.name.localeCompare(b.name));
Most Common just-*
import debounce from 'just-debounce-it';
import throttle from 'just-throttle';
import pick from 'just-pick';
import omit from 'just-omit';
import shuffle from 'just-shuffle';
import partition from 'just-partition';
// Debounce input handler
const handleInput = debounce(value => search(value), 300);
// Throttle scroll handler
const handleScroll = throttle(() => updatePosition(), 100);
// Pick specific keys
const subset = pick(user, ['id', 'name', 'email']);
// Omit sensitive keys
const safe = omit(user, ['password', 'token']);
// Shuffle array
const randomized = shuffle(cards);
// Split by condition
const [valid, invalid] = partition(inputs, x => x.isValid);
Decision Tree
- Can native API do it? → Use native (zero deps)
- Is it a one-liner? → Write inline
- Need tested edge cases? → Use
just-*
package
- Complex algorithm? → Use
just-*
package