diff --git a/src/async/reduce.ts b/src/async/reduce.ts index 690542f0..b3d2bd25 100644 --- a/src/async/reduce.ts +++ b/src/async/reduce.ts @@ -13,17 +13,33 @@ */ export async function reduce( array: readonly T[], - asyncReducer: (acc: K, item: T, index: number) => Promise, - initValue?: K, + reducer: (acc: K, item: T, index: number) => Promise, + initialValue: K, +): Promise +export async function reduce( + array: readonly T[], + reducer: (acc: K, item: T, index: number) => Promise, +): Promise +export async function reduce( + array: readonly T[], + reducer: (acc: K, item: T, index: number) => Promise, + initialValue?: K, ): Promise { - const initProvided = initValue !== undefined - if (!initProvided && array?.length < 1) { - throw new Error('Cannot reduce empty array with no init value') + if (!array) { + array = [] + } + const indices = array.keys() + let acc = initialValue + // biome-ignore lint/style/noArguments: + if (acc === undefined && arguments.length < 3) { + if (!array.length) { + throw new TypeError('Reduce of empty array with no initial value') + } + acc = array[0] as any + indices.next() } - const iter = initProvided ? array : array.slice(1) - let value: any = initProvided ? initValue : array[0] - for (const [i, item] of iter.entries()) { - value = await asyncReducer(value, item, i) + for (const index of indices) { + acc = await reducer(acc!, array[index], index) } - return value + return acc! } diff --git a/tests/async/reduce.test.ts b/tests/async/reduce.test.ts index 4a162410..eefa16f6 100644 --- a/tests/async/reduce.test.ts +++ b/tests/async/reduce.test.ts @@ -3,21 +3,15 @@ import * as _ from 'radashi' const cast = (value: any): T => value describe('asyncReduce', () => { + const numbers = [0, 1, 2, 3, 4] + const reducer = async (a: number, b: number): Promise => { + return new Promise(res => res(a + b)) + } beforeEach(() => { vi.useFakeTimers({ shouldAdvanceTime: true }) }) test('returns result of reducer', async () => { - const numbers = [ - 0, - 1, - 2, - 3, - 4, // => 10 - ] - const asyncSum = async (a: number, b: number): Promise => { - return new Promise(res => res(a + b)) - } - const result = await _.reduce(numbers, asyncSum, 0) + const result = await _.reduce(numbers, reducer, 0) expect(result).toBe(10) }) test('passes correct indexes', async () => { @@ -35,41 +29,18 @@ describe('asyncReduce', () => { const result = await _.reduce(array, asyncSumIndex, []) expect(result).toEqual([0, 1, 2, 3, 4]) }) -}) - -describe('reduce/asyncReduceV2', () => { - const numbers = [0, 1, 2, 3, 4] - const reducer = async (a: number, b: number): Promise => { - return new Promise(res => res(a + b)) - } - - beforeEach(() => { - vi.useFakeTimers({ shouldAdvanceTime: true }) - }) - test('calls asyncReduce', async () => { - const result = await _.reduce(numbers, reducer, 0) - expect(result).toBe(10) - }) test('uses first item in array when no init provided', async () => { const result = await _.reduce(numbers, reducer) expect(result).toBe(10) }) test('throws on no init value and an empty array', async () => { - try { - await _.reduce([], reducer) - } catch (err) { - expect(err).not.toBeNull() - return - } - expect.fail('Expected error to be thrown') + await expect(async () => _.reduce([], reducer)).rejects.toThrowError( + 'Reduce of empty array with no initial value', + ) }) test('throws on no init value and a null array input', async () => { - try { - await _.reduce(cast(null), reducer) - } catch (err) { - expect(err).not.toBeNull() - return - } - expect.fail('Expected error to be thrown') + await expect(async () => + _.reduce(cast(null), reducer), + ).rejects.toThrowError('Reduce of empty array with no initial value') }) })