https://github.com/pallad-ts/compare
Custom sorting inspired by Rust
https://github.com/pallad-ts/compare
comparison custom-sorting nodejs sorting value-object
Last synced: about 1 month ago
JSON representation
Custom sorting inspired by Rust
- Host: GitHub
- URL: https://github.com/pallad-ts/compare
- Owner: pallad-ts
- License: mit
- Created: 2021-06-23T08:55:18.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2022-12-05T16:23:25.000Z (over 3 years ago)
- Last Synced: 2025-02-15T05:05:20.331Z (over 1 year ago)
- Topics: comparison, custom-sorting, nodejs, sorting, value-object
- Language: TypeScript
- Homepage:
- Size: 300 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
compare ⬆️⬇️️
Custom sorting inspired by Rust
---
[](https://circleci.com/gh/pallad-ts/compare/tree/master)
[](https://badge.fury.io/js/@pallad%2Fcompare)
[](https://coveralls.io/github/pallad-ts/compare?branch=master)
[](https://opensource.org/licenses/MIT)
---

Sorting library inspired by [Rust's Ordering](https://doc.rust-lang.org/std/cmp/enum.Ordering.html).
Allows to easy definition of comparison abilities for your objects, especially value objects.
# Community
Join our [discord server](https://discord.gg/cbpxw93DnS)
# Installation
```shell
npm install @pallad/compare
```
# Usage
Comparing two values of same type
```typescript
import {compare} from '@pallad/compare';
compare(1, 2).isLess // true
compare(1, 2).isGreater // false
compare(1, 2).isEqual // false
```
## Sorting
`compare` first tries to leverage `compare` defined by `Comparable` interface if that is possible.
Otherwise fallbacks to regular operators (`<`, `==`, `>`) comparison .
```typescript
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.
```typescript
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 // false
```
You do not need to pass comparator all the time, just create own compare function.
```typescript
import {createCompareWithComparator} from '@pallad/compare';
const customCompare = createCompareWithComparator(comparator);
customCompare(aValue, bValue).isGreater // true
customCompare.reverse(aValue, bValue).isGreater // false
```
## Defining custom sorting for value objects
```typescript
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); // Less
```
# Explanation
As in Rust's `Ordering` - `@pallad/compare` uses 3 immutable objects to describe the comparison result.
The result could be:
* `Less`
* `Equal`
* `Greater`
Each of them implements following shape:
```typescript
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
```typescript
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
```typescript
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 👌
```