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