compareBy<T>() multi-key sort comparator
TypeScript
export type Direction = 'asc' | 'desc';
export interface SortKey<T> {
value: (row: T) => string | number | Date | null | undefined;
direction?: Direction;
nullsLast?: boolean;
}
/** Build a stable multi-key comparator with null placement per key. */
export function compareBy<T>(keys: readonly SortKey<T>[]): (a: T, b: T) => number {
return (a, b) => {
for (const key of keys) {
const left = key.value(a);
const right = key.value(b);
const nullsLast = key.nullsLast ?? true;
if (left == null || right == null) {
if (left == null && right == null) continue;
return left == null ? (nullsLast ? 1 : -1) : nullsLast ? -1 : 1;
}
let delta: number;
if (left instanceof Date && right instanceof Date) {
delta = left.getTime() - right.getTime();
} else if (typeof left === 'string' && typeof right === 'string') {
delta = left.localeCompare(right, undefined, { sensitivity: 'base', numeric: true });
} else if (typeof left === 'number' && typeof right === 'number') {
delta = left - right;
} else {
delta = String(left).localeCompare(String(right));
}
if (delta !== 0) return key.direction === 'desc' ? -delta : delta;
}
return 0;
};
}
// rows.sort(compareBy([{ value: (r) => r.team }, { value: (r) => r.score, direction: 'desc' }]));