Very simple structure with helper methods to define range of values in following scenarios
- from A
- to A
- between A and B
Join our discord server
npm install @pallad/range
Range
consists of 3 different interfaces
Range.Start
that defines only a start without an end.
interface Start<T> {
start: T
}
Range.End
that defines only an end without a start.
interface End<T> {
end: T;
}
Range.Full
that defines both a start and an end.
type Full<T> = Start<T> & End<T>
The Range
type itself is an union of all of them.
type Range<T> = Range.Full<T> | Range.Start<T> | Range.End<T>;
You can create Range
from regular creation function, array or tuple.
Regular create
// full range
Range.create(1, 100);
// start range
Range.create(1);
// end range
Range.create(undefined, 100);
From array or Tuple
// start range
Range.fromArray([1])
// full range
Range.fromArray([1, 100])
// full range - other values are ignores
Range.fromArray([1, 100, 1003, 3000])
// end range
Range.fromArray([undefined, 100])
If creation fails, TypeError
is thrown.
// fails - undefined values
Range.create(undefined, null)
// fails - start greater than end
Range.create(100, 1)
// fails - empty array
Range.fromArray([])
// fails - undefined values only
Range.fromArray([undefined, null])
Range.create(1, 100).value;
Range.create(null, undefined).value // 'Cannot create Range from undefined or null values'
Enchanted range is a range object with extra methods. Enchanted object is immutable.
const enchantedRange = enchant(Range.create(1, 100));
enchantedRange.isWithin(40); // true
enchantedRange.isWithin(500); // false
enchantedRange.map({
start: ({start}) => `from ${start}`,
end: ({end}) => `to ${end}`,
full: ({start, end}) => `between ${start} and ${end}`
}); // 'between 1 and 100`
enchantedRange.toTuple(); // [1, 100]
Range.is({start: 10}) // true
Range.is({end: 10}) // true
Range.is({start: 1, end: 10}) // true
Boundaries comparison is a crucial feature of Range
struct, therefore internally uses @pallad/compare
for
comparison.
Sometimes it is not enough and you can provide your
own comparison function.
Range.create({value: 1}, {value: 100}, (a, b) => a.value - b.value); // no fail
Range.fromArray([{value: 1}, {value: 100}], (a, b) => a.value - b.value); // no fail
Mapping converts range to any other value.
Range.map
accepts object with properties named start
, end
and full
where each of it might be a function or any
other value.
If property value is a function then result of that function gets returned, otherwise it takes the value.
const range = Range.create(1, 100);
// mapping to simple values
Range.map(range, {start: 'start', end: 'end', full: 'full'}) // 'full'
// mapping functions
enchantedRange.map({
start: ({start}) => `from ${start}`,
end: ({end}) => `to ${end}`,
full: ({start, end}) => `between ${start} and ${end}`
}); // 'between 1 and 100`
Range.isWithin
checks if given values falls in range. Internally uses @pallad/compare
so custom comparison functions
for value objects are supported.
Range.isWithin(Range.create(1, 100), 50) // true
Range.isWithin(Range.create(1, 100), 500) // false
By default isWithin
treats every range as inclusive for both edges. You can change that behavior with second argument.
const range = Range.create(1, 100);
// exclusivity = false
Range.isWithin(range, 100, false) // true
Range.isWithin(range, 1, false) // true
// same as above
Range.isWithin(range, 100) // true
Range.isWithin(range, 1) // true
// exclusivity = true
Range.isWithin(range, 100, true) // false
Range.isWithin(range, 1, true) // false
// start exclusive
Range.isWithin(range, 100, {start: true}) // true
Range.isWithin(range, 1, {start: true}) // false
// end exclusive
Range.isWithin(range, 100, {end: true}) // false
Range.isWithin(range, 1, {end: true}) // true
Range.convert(Range.create(1, 100), (value) => value + 's'); // Range<string> { start: '1s', end: '100s' }
Range.convert(Range.create(1), (value) => value + 's'); // Range<string> { start: '1s'}
Range.convert(Range.create(undefined, q00), (value) => value + 's'); // Range<string> { end: '100s'}
Sometimes you need to map to values that cannot be easily compared, therefore you need to provide custom comparison function to ensure proper creation of new range
const range = Range.create(2, 100);
// custom comparison function is needed since '2s' > '100s' using regular string comparison
Range.convert(range, (value) => value + 's', (a, b) => parseInt(a) - parseInt(b));