ts-order
Version:
Type-safe Order utility for delarative, composable, and immutable multi-key ordering logic
197 lines (195 loc) • 6.15 kB
text/typescript
import { Comparator, Direction, KeyOptions } from "./types-s6KM5rLp.cjs";
//#region src/order.d.ts
/**
* Builder for immutable multi-step ordering rules.
*
* Create an `Order`, chain `.by()` calls to describe each step, then use
* `.compare` with `Array.prototype.sort` or call `.sort()` for DSU-style sorting
* that evaluates keys only once per step.
*
* @example
* ```ts
* const byStatusThenName = new Order<User>()
* .by((u) => u.isActive, { direction: 'desc' })
* .by((u) => u.lastName)
* .by((u) => u.firstName);
*
* users.sort(byStatusThenName.compare);
* ```
*/
declare class Order<T> {
private _steps;
/**
* Create a new order. When a source or iterable of sources is provided, the
* new order copies every step from the input.
*
* @example
* ```ts
* // Create an empty order and append steps to it:
* const base = new Order<User>();
* const byScore = base.by((u) => u.score);
*
* // Or combine multiple orders together:
* const byScoreThenId = new Order([base, Order.by((u: User) => u.id)]);
* ```
*/
constructor();
constructor(source: Order<T> | null | undefined);
constructor(sources: Iterable<Order<T> | null | undefined>);
/**
* Create a new order with a single sort step.
*
* @example
* ```ts
* const byCreatedAt = Order.by((u: User) => u.createdAt, {
* direction: 'desc',
* });
* ```
*/
static by<T, K>(selectorFn: (item: T) => K, options?: KeyOptions<K, T>): Order<T>;
/**
* Append a sort step and return a new order instance.
*
* @example
* ```ts
* const byCreatedThenId = new Order<User>()
* .by((u) => u.createdAt)
* .by((u) => u.id);
* ```
*/
by<K>(selectorFn: (item: T) => K, options?: KeyOptions<K, T>): Order<T>;
/**
* Flip the direction of every step in an order.
*
* @example
* ```ts
* const newestFirst = Order.reverse(Order.by((u: User) => u.createdAt));
* ```
*/
static reverse<T>(input: Order<T>): Order<T>;
/**
* Flip the direction of every step in this order.
*
* @example
* ```ts
* const newestFirst = Order.by((u: User) => u.createdAt).reverse();
* ```
*/
reverse(): Order<T>;
/**
* Lifts an order defined for a derived or nested value into the parent domain.
* The provided mapping function extracts the inner value, and the given order
* is applied to that value when comparing parent items.
*
* @example
* ```ts
* interface Address {
* city: string;
* postcode: string;
* }
* interface Customer {
* id: number;
* address: Address;
* }
* const byAddress = Order.by((a: Address) => a.city).by((a) => a.postcode);
* const byCustomerAddress = Order.map((c: Customer) => c.address, byAddress);
* ```
*/
static map<T, K>(outer: (t: T) => K, sub: Order<K>): Order<T>;
/**
* Appends additional sort steps that only apply when both compared items satisfy the given predicate.
* If either item fails the predicate, the appended steps are skipped and sorting continues
* with the next step in the current `Order`.
*
* @example
* ```ts
* const euPriority = Order.when(
* (u: User) => u.region === 'eu',
* Order.by((u: User) => u.score, { direction: 'desc' }),
* );
* ```
*/
static when<T>(predicate: (value: T) => boolean, input: Order<T>): Order<T>;
/**
* Lifts an order defined for a derived or nested value into the parent domain.
* The provided mapping function extracts the inner value, and the given order
* is applied to that value when comparing parent items.
*
* @example
* ```ts
* interface Address {
* city: string;
* postcode: string;
* }
* interface Customer {
* id: number;
* address: Address;
* }
* const byIdThenAddress = new Order<Customer>()
* .by((c) => c.id)
* .map((c) => c.address, byAddress);
* ```
*/
map<K>(outer: (t: T) => K, sub: Order<K>): Order<T>;
/**
* Appends additional sort steps that only apply when both compared items satisfy the given predicate.
* If either item fails the predicate, the appended steps are skipped and sorting continues
* with the next step in the current `Order`.
*
* @example
* ```ts
* const byRegion = new Order<User>()
* .by((u) => u.region)
* .when(
* (u) => u.region === 'eu',
* Order.by((u) => u.score, { direction: 'desc' }),
* )
* // Append a final tiebreaker (runs for all items)
* .by((u) => u.id);
* ```
*/
when(predicate: (value: T) => boolean, order: Order<T>): Order<T>;
/**
* Retrieve a comparator compatible with `Array.prototype.sort`.
*
* @example
* ```ts
* users.sort(Order.by((u: User) => u.id).compare);
* ```
*/
get compare(): (a: T, b: T) => number;
/**
* Sort an array with the provided order and return a new array.
*
* This method implements the Schwartzian Transform or DSU
* (decorate-sort-undecorate) technique, which ensures that each key
* selector is only invoked once per element per step. For larger arrays or
* costly key computations, this can yield significant performance
* improvements over repeatedly calling the selector during comparisons.
*
* @example
* ```ts
* const out = Order.sort(users, Order.by((u: User) => u.lastName));
* ```
*/
static sort<T>(array: readonly T[], order: Order<T>): T[];
/**
* Sort an array with the provided order and return a new array.
*
* This method implements the Schwartzian Transform or DSU
* (decorate-sort-undecorate) technique, which ensures that each key
* selector is only invoked once per element per step. For larger arrays or
* costly key computations, this can yield significant performance
* improvements over repeatedly calling the selector during comparisons.
*
* @example
* ```ts
* const sorted = Order.by((u: User) => u.lastName).sort(users);
* ```
*/
sort(array: readonly T[]): T[];
/** Replace the internal step list with provided steps. */
private _assignSteps;
}
//#endregion
export { type Comparator, type Direction, type KeyOptions, Order };