reduce
The reduce utility reduces an array to a single value by executing a reducer function on each element, passing in the return value from the calculation on the preceding element.
Implementation
View Source Code
ts
import { assert } from '../function/assert';
import { IS_ARRAY_ERROR_MSG, isArray } from '../typed/isArray';
import { isPromise } from '../typed/isPromise';
import type { Result } from '../types';
type SyncCallback<R, T> = (prev: R, curr: T, index: number, array: T[]) => R;
type AsyncCallback<R, T> = (prev: R, curr: T, index: number, array: T[]) => Promise<R>;
type Callback<R, T> = SyncCallback<R, T> | AsyncCallback<R, T>;
/**
* Reduces an array to a single value by applying a callback function
* to each element in the array, passing the accumulated result and
* the current element as arguments. Supports both synchronous and
* asynchronous callback functions.
*
* @example
* ```ts
* const arr = [1, 2, 3];
* reduce(arr, (acc, curr) => acc + curr, 0); // 10
* await reduce(arr, async (acc, curr) => acc + curr, 0); // 10
* ```
*
* @param array - The array to reduce.
* @param callback - The callback function to apply to each element.
* @param initialValue - The initial value for the accumulator.
*
* @returns The reduced value, or a Promise that resolves to the reduced value if the callback is asynchronous.
*
* @throws {TypeError} If the first argument is not an array.
*/
export function reduce<T, R, C extends Callback<R, T>>(array: T[], callback: C, initialValue: R) {
assert(isArray(array), IS_ARRAY_ERROR_MSG, { args: { array }, type: TypeError });
const lazy = isPromise(callback);
let acc: R | Promise<R> = lazy ? Promise.resolve(initialValue) : initialValue;
for (let i = 0; i < array.length; i++) {
if (lazy) {
acc = (acc as Promise<R>).then((resolvedAcc) => callback(resolvedAcc, array[i], i, array));
} else {
acc = callback(acc as R, array[i], i, array);
}
}
return acc as Result<C>;
}
reduce.fn = true;Features
- Isomorphic: Works in both Browser and Node.js.
- Type-safe: Correctly handles types for both elements and the accumulator.
- Async Support: If the callback returns a Promise,
reducewill return a Promise that resolves to the final value once all elements are processed sequentially.
API
ts
function reduce<T, R>(
array: T[],
callback: (acc: R, item: T, index: number, array: T[]) => R | Promise<R>,
initialValue: R,
): R | Promise<R>;Parameters
array: The array to reduce.callback: The reducer function called for every element. It receives:acc: The accumulated value.item: The current element.index: The index of the current element.array: The original array.
initialValue: The value to use as the first argument to the first call of the callback.
Returns
- The accumulated result.
- A
Promise<R>if the callback is asynchronous.
Examples
Basic Aggregation
ts
import { reduce } from '@vielzeug/toolkit';
const numbers = [1, 2, 3, 4];
const sum = reduce(numbers, (acc, x) => acc + x, 0); // 10Building Objects
ts
import { reduce } from '@vielzeug/toolkit';
const pairs: [string, number][] = [
['a', 1],
['b', 2],
['c', 3],
];
const obj = reduce(
pairs,
(acc, [key, val]) => {
acc[key] = val;
return acc;
},
{} as Record<string, any>,
);
// { a: 1, b: 2, c: 3 }Asynchronous Reduction
ts
import { reduce, delay } from '@vielzeug/toolkit';
const tasks = [1, 2, 3];
const result = await reduce(
tasks,
async (acc, task) => {
await delay(100); // Process task sequentially
return acc + task;
},
0,
); // 6Implementation Notes
- Throws
TypeErrorif the first argument is not an array. - Sequential Execution: Unlike
mapandfilter, asynchronousreduceprocesses elements one after another, as the next call depends on the previous result.