@cubux/readonly-array
A bunch of helper functions to work with read-only arrays. Works internally with native arrays without any kind of magic.
import { insert, remove } from '@cubux/readonly-array';
const input: readonly number[] = [10, 20, 30];
console.log(insert(input, 1, 42, 37));
// => [10, 42, 37, 20, 30]
console.log(remove(input, 1));
// => [10, 30]
console.log(remove(input, 1, 2));
// => [10]
Alternative usage:
import * as RoArray from '@cubux/readonly-array';
const input: readonly number[] = [10, 20, 30];
console.log(RoArray.insert(input, 1, 42, 37));
// => [10, 42, 37, 20, 30]
Use Cases
State management
import { FC, useState } from 'react';
import { insert, remove, set } from '@cubux/readonly-array';
const TodoList: FC = () => {
const [items, setItems] = useState<readonly string[]>([]);
return (
<ul>
{items.map((item, i) => (
<li key={i}>
<button
onClick={() => setItems(list => insert(list, i, ''))}
>
INS
</button>
<button
onClick={() => setItems(list => remove(list, i))}
>
DEL
</button>
<input
value={item}
onChange={(e) => setItems(list => set(list, i, e.target.value))}
/>
</li>
))}
<li>
<button onClick={() => setItems(list => [...list, ''])}>ADD</button>
</li>
</ul>
);
};
Install
npm i @cubux/readonly-array
API
append()
append(
array: readonly T[],
...items: readonly T[],
): readonly T[]
Creates a new array containing items from input array
and extra ...items
in
the end.
- Will return input
array
without changes when nothing to append.
const input = [10, 20, 30];
append(input, 40, 50);
// [10, 20, 30, 40, 50]
NOTICE: By default this function should be avoided when you surely add at least one element:
// Better
[...array, item1, item2]
// Instead of
append(array, item1, item2)
So, when appending items count can be zero:
// This will always create new array
[...array, ...addItems]
// But this will return origin `array` when `addItems` is empty array
append(array, ...addItems)
insert()
insert(
array: readonly T[],
index: number,
...items: readonly T[],
): readonly T[]
Creates new array by inserting new ...items
into input array
in offset
index
.
- Will throw
RangeError
whenindex
is invalid. - Will return input
array
without changes when nothing to insert. - Allow appending with
index = array.length
.
const input = [10, 20, 30];
insert(input, 2, 40, 50);
// [10, 20, 40, 50, 30]
remove()
remove(
array: readonly T[],
start: number,
length: number = 1,
): readonly T[]
Creates new array by omitting length
items from input array
at start
offset.
- Will throw
RangeError
whenindex
is invalid orlength
is negative. - Will return input
array
when length is0
. - Value of
length
can safely lead out ofarray.length
.
const input = [10, 20, 30, 40];
remove(input, 1); // => [10, 30, 40]
remove(input, 1, 2); // => [10, 40]
remove(input, 1, 10); // => [10]
removeMatch()
removeMatch<T>(
array: readonly T[],
removePredicate: (value: T, index: number) => unknown,
limit: number = 1,
): readonly T[]
Remove items matching the given predicate
Creates new array from the input array
by omitting items matching
predicate removePredicate
. This is opposite to Array.prototype.filter()
.
Positive limit
(defaults to 1
) will omit at most that number of items.
Negative limit
means "no limit".
- Will return input
array
when it's nothing to change.
const input = [10, 20, 30, 40];
removeMatch(input, (v) => v % 20 === 0);
// => [10, 30, 40]
removeMatch(input, (v) => v % 10 === 0, 2);
// => [30, 40]
removeMatch(input, (v) => v % 2);
// => [10, 20, 30, 40]
removeMatch(input, (v) => v % 2 === 0, -1);
// => []
set()
set(
array: readonly T[],
index: number,
value: T,
): readonly T[]
Creates new array from input array
with item at offset index
changed to
value
.
- Will throw
RangeError
whenindex
is invalid. - Will return input
array
when nothing to change (===
check).
const input = [10, 20, 30, 40];
set(input, 2, 42);
// => [10, 20, 42, 40]
// instead of
const next = [...input];
next[2] = 42;
next
swap()
swap(
array: readonly T[],
i: number,
j: number,
): readonly T[]
Creates new array from source array
by swapping two items at indices i
and
j
.
- Will throw
RangeError
when eitheri
orj
is invalid. - Will return input
array
when nothing to change (===
check for indices and items values).
const input = [10, 20, 30, 40];
swap(input, 2, 3);
// => [10, 30, 20, 40]
update()
update(
array: readonly T[],
index: number,
updater: (prev: T, index: number) => T,
): readonly T[]
Creates new array from input array
with item at offset index
changed with
a given callback updater
. A callback updater(prev, index)
will receive
previous value and index.
- Will throw
RangeError
whenindex
is invalid. - Will return input
array
when nothing to change (===
check).
const input = [10, 20, 30, 40];
update(input, 2, (v, i) => 1000 * i + v);
// => [10, 20, 2030, 40]
updateMatch()
update(
array: readonly T[],
predicate: (value: T, index: number) => T,
updater: (prev: T, index: number) => T,
limit: number = 1,
): readonly T[]
Creates new array from input array
with some item matching predicate
(at
most limit
) updated by updater
.
Callbacks predicate(value, index)
and updater(prev, index)
will receive item
value and index. The predicate
returns whether the given item need be updated.
The updater
will be called for those items matched by predicated
until
limit
exceeds.
Positive limit
(defaults to 1
) will update at most that number of items.
Negative limit
means "no limit".
-
limit
applies topredicate
only without care if some previous item was actually changed byupdater
. - Will return input
array
when nothing to change (===
check).
const input = [10, 20, 30, 40];
updateMatch(input, v => v % 20 === 0, (v, i) => 1000 * i + v);
// => [10, 1020, 30, 40]