import { assert } from "../../diagnostics"; import { checkArgumentType, InvalidOperationError } from "../../errors"; import { PipeBody, PipeFunction } from "../../pipables"; import type { LinqWrapper } from "../linqWrapper"; export type AggregateAccumulator = (accumulate: TAccumulate, element: T) => TAccumulate; const MissingValueSymbol = Symbol("MissingValue"); export function aggregate(seed: TAccumulate, accumulator: AggregateAccumulator): PipeBody, TAccumulate>; export function aggregate(accumulator: AggregateAccumulator): PipeBody, T>; export function aggregate( arg1: TAccumulate | AggregateAccumulator, accumulator?: AggregateAccumulator, ): PipeBody, TAccumulate> { return target => { const [seed, acc] = accumulator ? [arg1 as TAccumulate, accumulator] as const : [MissingValueSymbol, arg1 as AggregateAccumulator] as const; checkArgumentType(accumulator ? 1 : 0, "accumulator", acc, "function"); let cur = seed; for (const e of target.unwrap()) { if (cur == MissingValueSymbol) { // This means T == TAccumulate cur = e as unknown as TAccumulate; assert(cur !== MissingValueSymbol); continue; } cur = acc(cur, e); } if (cur == MissingValueSymbol) throw new InvalidOperationError("Sequence contains no element as initial value."); return cur; }; } aggregate satisfies PipeFunction;