Array
Utilities for transforming, grouping, and structuring arrays. Import from the root or from koyojs/Array.
// Root import
import { chunk, flatten, unique, groupBy, createArray } from "koyojs";
// Per-module import
import { chunk } from "koyojs/Array";Splits an array into sub-arrays of the given size. The last chunk may be smaller if the array length is not evenly divisible.
| Parameter | Type | Description |
|---|---|---|
arr | T[] | The source array. |
size | number | The maximum length of each chunk. Must be a positive integer. |
| returns | T[][] | — |
import { chunk } from "koyojs";
chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
chunk(["a","b","c","d"], 3); // [["a","b","c"], ["d"]]
chunk([], 2); // []
// Pagination — split all items into pages of 10
const pages = chunk(allProducts, 10);
const currentItems = pages[pageIndex] ?? [];
// Batch API requests — process 50 IDs at a time to avoid rate limits
const batches = chunk(userIds, 50);
for (const batch of batches) {
await api.bulkUpdate(batch);
}
// Render a fixed 3-column grid
const rows = chunk(items, 3);
rows.map(row => (
<div class="grid-row">
{row.map(item => <Card item={item} />)}
</div>
));Recursively flattens a nested array of any depth into a single flat array.
| Parameter | Type | Description |
|---|---|---|
arr | unknown[] | The nested array to flatten. |
| returns | T[] | — |
import { flatten } from "koyojs";
flatten([1, [2, 3], [4, [5, 6]]]); // [1, 2, 3, 4, 5, 6]
flatten([[["a"]], ["b"], "c"]); // ["a", "b", "c"]
flatten([]); // []
// Collect all tags from multiple blog posts into one list
const posts = [
{ title: "Intro to TS", tags: ["typescript", "beginner"] },
{ title: "Advanced TS", tags: ["typescript", "advanced"] },
{ title: "SolidJS Guide", tags: ["solidjs", "frontend"] },
];
const allTags = flatten(posts.map(p => p.tags));
// ["typescript", "beginner", "typescript", "advanced", "solidjs", "frontend"]
// Flatten a matrix into a 1D array
const matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
flatten(matrix); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Normalize API response with nested arrays
const categorized = await fetch("/api/products").then(r => r.json());
// { featured: [...], popular: [...], new: [...] }
const allProducts = flatten(Object.values(categorized));Returns a new array with all duplicate values removed. Preserves the order of first occurrence. `removeDuplicates` is an alias for the same function.
| Parameter | Type | Description |
|---|---|---|
arr | T[] | The input array. |
| returns | T[] | — |
import { unique, removeDuplicates } from "koyojs";
unique([1, 2, 2, 3, 1, 4]); // [1, 2, 3, 4]
unique(["a", "b", "a", "c"]); // ["a", "b", "c"]
unique([]); // []
// removeDuplicates is an alias — identical behaviour
removeDuplicates([1, 1, 2]); // [1, 2]
// Deduplicate tags entered by a user
const rawTags = ["js", "typescript", "js", "css", "typescript"];
const tags = unique(rawTags); // ["js", "typescript", "css"]
// Collect unique user IDs from an event log
const activeUserIds = unique(events.map(e => e.userId));
// Merge two lists without duplicates
const merged = unique([...existingItems, ...newItems]);
// Get all distinct categories from a product catalog
const categories = unique(products.map(p => p.category));Groups the elements of an array into an object keyed by the string returned by `keyFn`. Each key maps to an array of all elements that produced that key.
| Parameter | Type | Description |
|---|---|---|
arr | T[] | The array to group. |
keyFn | (item: T) => string | A function that receives each element and returns the group key. |
| returns | Record<string, T[]> | — |
import { groupBy } from "koyojs";
// Group employees by department
const people = [
{ name: "Alice", dept: "eng" },
{ name: "Bob", dept: "design" },
{ name: "Carol", dept: "eng" },
];
groupBy(people, p => p.dept);
// {
// eng: [{ name: "Alice", dept: "eng" }, { name: "Carol", dept: "eng" }],
// design: [{ name: "Bob", dept: "design" }],
// }
// Group numbers by parity
groupBy([1, 2, 3, 4, 5], n => n % 2 === 0 ? "even" : "odd");
// { odd: [1, 3, 5], even: [2, 4] }
// Group orders by status for a dashboard
const grouped = groupBy(orders, o => o.status);
const pendingCount = grouped.pending?.length ?? 0;
const shippedCount = grouped.shipped?.length ?? 0;
const deliveredCount = grouped.delivered?.length ?? 0;
// Group log entries by severity level
const logs = groupBy(entries, e => e.level); // { info: [...], warn: [...], error: [...] }Creates a type-enforced array that validates each element on push. When `strict` is true, pushing an invalid value throws a TypeError. When false, it logs a warning and silently drops the value. An optional `validate` predicate lets you enforce any type or shape beyond primitives.
| Parameter | Type | Description |
|---|---|---|
options.strict | boolean | If true, invalid pushes throw TypeError. If false, they warn and are silently dropped. |
options.validate | (value: unknown) => value is T | Optional type guard. Defaults to checking the type of the first element pushed. |
| returns | TypedArray<T> | — |
import { createArray } from "koyojs";
// Strict number array — throws on bad input
const nums = createArray<number>({ strict: true });
nums.push(1, 2, 3); // ok
nums.push("oops"); // throws TypeError: expected number, got string
// Lenient string array — warns and skips invalid values
const tags = createArray<string>({
strict: false,
validate: (v): v is string => typeof v === "string",
});
tags.push("alpha", "beta"); // ok
tags.push(42); // console.warn, dropped silently
console.log(tags.items); // ["alpha", "beta"]
console.log(tags.toArray()); // ["alpha", "beta"] — plain JS array
// TypedArray is iterable
for (const tag of tags) console.log(tag);
// Custom shape validation for a typed entity list
interface Product { id: number; name: string; price: number }
const isProduct = (v: unknown): v is Product =>
typeof v === "object" && v !== null &&
"id" in v && "name" in v && "price" in v;
const cart = createArray<Product>({ strict: true, validate: isProduct });
cart.push({ id: 1, name: "Keyboard", price: 89.99 }); // ok
cart.push({ id: 2, name: "Mouse" }); // throws — missing price
// Get the total from a typed cart
import { sum } from "koyojs";
const total = sum(cart.items.map(p => p.price));