Zero deps
Pure TypeScript. No transitive dependencies. No supply chain risk.
Zero deps
Pure TypeScript. No transitive dependencies. No supply chain risk.
Ultra lightweight
~13 kB gzipped for the entire library. Most individual utilities weigh under 500 bytes.
Ultra simple
Named object params. One function, one job. No config, no magic.
Ultra fast
Up to 11x faster than lodash. Every utility is benchmarked.
Verbose by design
Declarative, readable names. Code that explains itself without comments.
Every utility is implemented in pure TypeScript using only built-in language features. The entire dependency tree is… nothing.
"dependencies": {}No transitive dependencies means no supply chain risk, no version conflicts, no surprise breaking changes from packages you’ve never heard of. What you install is what you get.
The entire library — all 59 utilities, tree-shaken — is ~13 kB gzipped. For comparison, lodash is ~24 kB and radash is ~12 kB. But you rarely ship the whole thing: each utility is a self-contained module you import individually, and tree-shaking drops the rest.
import { chunk } from "1o1-utils/chunk"; // 253 Bimport { pick } from "1o1-utils/pick"; // 498 Bimport { sleep } from "1o1-utils/sleep"; // 176 BPer-utility gzipped size for all 59 utilities. The Total is the whole tree-shaken library, not the sum of the rows — shared internals are counted once.
| Utility | Size |
|---|---|
| isNil | 77 B |
| once | 169 B |
| escapeRegExp | 170 B |
| sleep | 176 B |
| get | 189 B |
| clamp | 195 B |
| capitalize | 210 B |
| isEmpty | 212 B |
| truncate | 214 B |
| arrayToHash | 215 B |
| pipe | 217 B |
| shuffle | 217 B |
| slugify | 218 B |
| unique | 219 B |
| safely | 220 B |
| partition | 221 B |
| groupBy | 222 B |
| times | 235 B |
| debounce | 249 B |
| chunk | 253 B |
| mapValues | 255 B |
| range | 261 B |
| defaults | 271 B |
| secondsToTimeFormat | 272 B |
| isValidUrl | 280 B |
| replace | 283 B |
| diff | 288 B |
| mapKeys | 302 B |
| throttle | 309 B |
| deepMerge | 310 B |
| zip | 316 B |
| unzip | 318 B |
| defaultsDeep | 322 B |
| isValidEmail | 326 B |
| isMobile | 329 B |
| compact | 336 B |
| timeFormatToSeconds | 343 B |
| shallowEqual | 352 B |
| retry | 379 B |
| sortBy | 423 B |
| isCircular | 428 B |
| omit | 432 B |
| set | 437 B |
| randomInt | 445 B |
| parallel | 449 B |
| withTimeout | 475 B |
| pick | 498 B |
| flatten | 512 B |
| stringStrength | 521 B |
| unflatten | 582 B |
| waitForCondition | 588 B |
| toNumber | 604 B |
| cloneDeep | 611 B |
| copyToClipboard | 615 B |
| transformCase | 649 B |
| deepEqual | 821 B |
| generateString | 869 B |
| bindKey | 1.21 kB |
| isValidPhone | 1.55 kB |
| Whole library (tree-shaken) | ~13 kB |
Every utility stays under strict size limits enforced in CI. If a PR makes a utility heavier, the build fails.
No positional args. No guessing what the second parameter does. Every function call reads like English:
// lodash — what's the 2nd argument?_.chunk(array, 2);_.truncate(str, { length: 20, separator: "..." });_.sortBy(users, ["age"]);
// 1o1-utils — self-documentingchunk({ array, size: 2 });truncate({ str, length: 20, suffix: "..." });sortBy({ array: users, key: "age" });Each utility does exactly one thing. No overloaded signatures, no option objects with 15 fields, no implicit behavior. Read the source in under a minute.
Built with strict: true from day one. Full type inference, generics, and IntelliSense for every parameter — no @types/* package needed.
Function and parameter names are declarative and intentionally simple. You should never need to check the docs to understand what a call does:
// What does this do? You need to know the API._.keyBy(users, "id");_.uniqBy(items, "sku");_.get(obj, "a.b.c");
// What does this do? Read it out loud.arrayToHash({ array: users, key: "id" });unique({ array: items, key: "sku" });get({ obj, path: "a.b.c" });Names follow plain English — arrayToHash, not keyBy. unique, not uniqBy. deepMerge, not merge (which might or might not be deep). isEmpty, not empty (is it a verb or an adjective?).
Parameters are equally explicit: { array, key } instead of positional (collection, iteratee). { str, length, suffix } instead of (string, options). Every call site is self-documenting — your code becomes the documentation.
1o1-utils is consistently faster than lodash and radash on every operation it implements:
| Utility | vs lodash | vs radash | vs native |
|---|---|---|---|
| chunk | 4.9x faster | on par | on par |
| pick | 3.3x faster | on par | — |
| unique | 2.7x faster | 1.6x faster | on par |
| groupBy | 1.3x faster | on par | on par |
| arrayToHash | on par | on par | on par |
On specific dataset sizes, chunk reaches up to 11.4x faster than lodash.
Every utility includes a benchmark file. Run pnpm bench to reproduce locally.
See the full benchmark results for methodology and detailed numbers.