@pallad/compare
v1.2.0
Published
Custom sorting inspired by Rust
Maintainers
Readme

Sorting library inspired by Rust's Ordering.
Allows to easy definition of comparison abilities for your objects, especially value objects.
Community
Join our discord server
Installation
npm install @pallad/compareUsage
Comparing two values of same type
import {compare} from '@pallad/compare';
compare(1, 2).isLess // true
compare(1, 2).isGreater // false
compare(1, 2).isEqual // falseSorting
compare first tries to leverage compare defined by Comparable interface if that is possible.
Otherwise fallbacks to regular operators (<, ==, >) comparison .
import {compare} from '@pallad/compare';
[5, 1, 10].sort(compare); // [1, 5, 10]
[5, 1, 10].sort(compare.reverse); // [10, 5, 1]Defining custom sorting for any values
You can define your own custom comparator that is used even if values are Comparable values.
import {compare} from '@pallad/compare';
interface Option {
type: string;
value: string;
}
function comparator(a: Option, b: Option) {
return a.type.localeCompare(b.type);
}
const aValue: Option = {
type: '2',
value: 'Option 2'
};
const bValue: Option = {
type: '1',
value: 'Option 1'
};
compare(aValue, bValue, comparator).isGreater // true
compare.reverse(aValue, bValue, comparator).isGreater // falseYou do not need to pass comparator all the time, just create own compare function.
import {createCompareWithComparator} from '@pallad/compare';
const customCompare = createCompareWithComparator(comparator);
customCompare(aValue, bValue).isGreater // true
customCompare.reverse(aValue, bValue).isGreater // falseDefining custom sorting for value objects
import {Comparable, Equal, Less, Greater} from '@pallad/compare';
class Money implements Comparable {
constructor(readonly value: number, readonly currency: string) {
}
compare(another: Money) {
if (another.currency !== this.currency) {
throw new Error('Cannot compare values with different currencies');
}
if (another.value === this.value) {
return Equal;
} else if (this.value < another.value) {
return Less
}
return Greater;
}
}
const amountA = new Money(100, 'BGP');
const amountB = new Money(200, 'BGP');
amountA.compare(amountB) // Less
// uses `compare` since it is defined
compare(amountA, amountB); // LessExplanation
As in Rust's Ordering - @pallad/compare uses 3 immutable objects to describe the comparison result.
The result could be:
LessEqualGreater
Each of them implements following shape:
interface Result {
type: 'equal' | 'less' | 'greater',
/**
* Indicates that value is lower
*/
isLess: boolean;
/**
* Indicates that values are equal
*/
isEqual: boolean;
/**
* Indicates that values are not equal (less or greater only)
*/
isNotEqual: boolean;
/**
* Indicates that value is less or equal
*/
isLessOrEqual: boolean;
/**
* Indicates that value is greater or equal
*/
isGreaterOrEqual: boolean;
/**
* Indicates that value is greater
*/
isGreater: boolean;
/**
* Maps result to another value
*/
map(ifLess: T1, ifEqual: T2, ifGreater: T3): T1 | T2 | T3;
map({less: T1, equal: T2, greater: T3}): T1 | T2 | T3;
/**
* Returns opposite value to current one
*
* Less -> Greater
* Equal -> Equal
* Greater -> Less
*/
reverse: Result;
/**
* Just numeric value you can use in `.sort` functions
*/
sortResult: 0 | -1 | 1,
/**
* Just numeric value you can use in `.sort` functions to reverse sorting
*/
sortResultReversed: 0 | -1 | 1,
}Mapping
You can map comparison result to any other value
import {compare} from '@pallad/compare';
// using arguments for each value
const r1 = compare(1, 5).map('less', 'equal', 'greater') // 'less'
type R1 = typeof r1; // 'less' | 'equal' | 'greater'
// using object
const r2 = compare(1, 5).map({
less: 'less',
equal: 'equal',
greater: 'greater'
}) // 'less'
type R2 = typeof r2; // 'less' | 'equal' | 'greater'Mapping to boolean
Before your try to map to booleans, think if currently available helpers are not good enough
import {compare} from '@pallad/compare';
compare(1, 10).map(false, true, false); // Too explicit ⚠️
compare(1, 10).isEqual // better 👌
compare(1, 10).map(true, true, false); // Too explicit ⚠️
compare(1, 10).isLessOrEqual // better 👌