fast-sort
A zero-dependency, blazing-fast TypeScript sorting library for arrays and objects by one or more properties.
Repository Health
Technical Analysis
fast-sort is a lightweight, zero-dependency array sorting library for JavaScript and TypeScript. It provides a fluent, chainable API (sort(array).asc()/.desc()/.by()) that reads unambiguously, solving the classic readability problem of array.sort((a, b) => ...), where the sort direction isn’t obvious from the comparator’s return sign. It supports sorting flat arrays, sorting arrays of objects by a single string key or accessor function, and sorting by multiple properties with an independent direction per property.
Beyond the basic API, it handles null and undefined values automatically (sorting them to the bottom by default in both directions), supports natural/language-sensitive string sorting via a custom Intl.Collator-based comparer, and offers an in-place variant (inPlaceSort) for cases where mutating the original array is preferable to allocating a new one. The library ships prebuilt ESM, CommonJS, and UMD bundles with full TypeScript typings and zero runtime dependencies, at roughly 850 bytes gzipped.
What You Get
- Chainable
asc()/desc()/by()sort API that removes ambiguity from comparator functions - Multi-property sorting with an independent direction per property, including automatic tie-break recursion across keys
- Built-in null/undefined handling that sorts nil values to the bottom by default, and is overridable
- Natural/language-sensitive sorting support via a custom
Intl.Collator-based comparer createNewSortInstancefactory for building reusable sorters with custom comparers or in-place mutation- Prebuilt ESM, CommonJS, and UMD bundles with zero runtime dependencies and full TypeScript typings
Common Use Cases
- Sorting a list of UI table rows by a user-selected column and direction
- Sorting arrays of objects by multiple fields, e.g. users by last name then first name
- Sorting filenames or version-like strings in natural order instead of lexicographic order
- Mutating a large array in place during a hot path instead of allocating a sorted copy
Under The Hood
Architecture
fast-sort is implemented as a single, roughly 230-line TypeScript module (src/sort.ts) built around a functional factory pattern rather than classes. createNewSortInstance(opts) closes over comparer/inPlaceSorting options and returns a function that wraps an array in an object exposing asc/desc/by; the two package-level exports, sort and inPlaceSort, are simply pre-configured instances of that factory. Actual sorting dispatches through getSortStrategy, which inspects the shape of the caller’s sortBy argument (undefined, string key, accessor function, array of keys, or an {asc/desc} config object) and returns a plain (a, b) => number comparator handed to the native Array.prototype.sort. Multi-property sorting is handled by a small mutually-recursive helper (multiPropertySorterProvider) that walks the sort keys one at a time and only recurses into the next key when the current comparison ties, keeping average-case comparison cost close to a native single-key sort. There is no dependency injection or external state; the one thing that would ripple through consumers is a change to the shared defaultComparer’s null-handling semantics, since both sort and inPlaceSort depend on it.
Tech Stack
The library targets modern JS runtimes and ships zero runtime dependencies (an empty dependencies object in package.json). Source is TypeScript 4.2, compiled and bundled with Rollup (rollup-plugin-typescript2, rollup-plugin-uglify, rollup-plugin-copy) into three output formats declared via package.json’s exports map: CommonJS (dist/sort.cjs.js), ESM (dist/sort.mjs), and a minified UMD build (dist/sort.min.js), alongside generated .d.ts typings. Tests run under Mocha with ts-node/register and Chai assertions; a separate integration suite installs the built npm package and the raw dist bundle to verify the published artifact actually works, wired into the prepublishOnly/postpublish npm lifecycle hooks. Linting uses ESLint with the Airbnb base config plus @typescript-eslint.
Code Quality
Test coverage is extensive: the core spec file alone runs to over 800 lines, covering flat-array sorting, single- and multi-property object sorting, natural/Intl.Collator sorting, and null/undefined and non-array edge cases. The dedicated integration tests that install and exercise the actual npm-published package and the raw dist bundle are a notably rigorous step many libraries skip, catching packaging regressions unit tests alone would miss. The public API is fully typed via exported interfaces (IComparer, ISortBy, ISortByObjectSorter) rather than loose any signatures, and invalid sort configurations throw explicit, descriptive errors instead of failing silently. No CI workflow configuration was found in the cloned repository at the time of this scan, though the README references third-party vulnerability scanning of the published package.
API Design
The chainable sort(x).asc()/.desc()/.by() API directly addresses the readability problem of native Array.prototype.sort comparators, making the sort direction explicit in the method name rather than inferred from a comparator’s return sign. Getting started requires no boilerplate beyond an import and a single call. Multi-property sorting via array literals (.asc(['a', 'b'])) or per-field direction objects (.by([{asc: ...}, {desc: ...}])) avoids hand-written tie-break comparator chains that the native API would otherwise require. TypeScript overloads on createNewSortInstance distinguish inPlaceSorting: true from the default to correctly type the return value as a mutable versus readonly array. The one conceptual seam for newcomers is learning when to reach for by (per-field direction config) versus the simpler asc/desc shorthand.