diff --git a/src/reduce.ts b/src/reduce.ts
index 52749f5d..229109b8 100644
--- a/src/reduce.ts
+++ b/src/reduce.ts
@@ -4,21 +4,25 @@ import type Arrow from "./types/Arrow";
import type IterableInfer from "./types/IterableInfer";
import type ReturnValueType from "./types/ReturnValueType";
-function sync(f: (a: B, b: A) => B, acc: B, iterable: Iterable): B {
+function sync(
+ f: (a: Acc, b: T) => Acc,
+ acc: Acc,
+ iterable: Iterable,
+): Acc {
for (const a of iterable) {
acc = f(acc, a);
}
return acc;
}
-async function async(
- f: (a: B, b: A) => B,
- acc: Promise,
- iterable: AsyncIterable,
+async function async(
+ f: (a: Acc, b: T) => Acc,
+ acc: Promise,
+ iterable: AsyncIterable,
) {
for await (const a of iterable) {
// becauseof using es5, use `await`
- acc = await pipe1(acc, (acc) => f(acc as B, a));
+ acc = await pipe1(acc, (acc) => f(acc as Acc, a));
}
return acc;
}
@@ -27,19 +31,48 @@ async function async(
* Also known as foldl, this method boils down a list of values into a single value.
*
* @example
+ * You can reduce values into homogeneous type.
+ *
* ```ts
* const sum = (a:number, b:number) => a + b;
+ *
+ * // with implicit seed with first element
* reduce(sum, [1, 2, 3, 4]); // 10
+ *
+ * // with explicit seed
* reduce(sum, 0, [1, 2, 3, 4]); // 10
+ * ```
+ *
+ * You can reduce values into heterogeneous type.
+ *
+ * ```ts
+ * // reduce { id: number; score: number; } to number
+ * reduce((acc, value) => acc + value.score, 0, [
+ * { id: 0, score: 1 },
+ * { id: 5, score: 2 },
+ * { id: 9, score: 3 },
+ * { id: 3, score: 4 }
+ * ])
+ * ```
+ *
+ * Omitting iterable will returns function, useful when using with pipe.
*
- * // with pipe
+ * ```ts
* pipe(
* [1, 2, 3, 4],
* map(a => a + 10),
* filter(a => a % 2 === 0),
* reduce(sum),
* ); // 26
+ * ```
+ *
+ * Currently, type with explicit seed form can't be inferred properly due to the limitation of typescript.
+ * But you can still use mostly with @ts-ignore flag. For more information please visit issue.
*
+ * {@link https://github.com/marpple/FxTS/issues/239 | #related issue}
+ *
+ *
+ * ```ts
* await pipe(
* Promise.resolve([1, 2, 3, 4]),
* map((a) => a + 10),
@@ -70,52 +103,66 @@ async function async(
*
* see {@link https://fxts.dev/docs/pipe | pipe}, {@link https://fxts.dev/docs/toAsync | toAsync},
* {@link https://fxts.dev/docs/map | map}, {@link https://fxts.dev/docs/filter | filter}
+ *
+ * @typeParam T - Type of values in `iterable` which would be consummed.
+ * @typeParam Acc - Type of `acc` which is the type of accumulative value
*/
-function reduce(f: Arrow, seed: B, iterable: A): B;
-
-function reduce(f: (a: A, b: A) => A, iterable: Iterable): A;
-
-function reduce(f: (a: B, b: A) => B, iterable: Iterable): B;
-
-function reduce(f: (a: B, b: A) => B, seed: B, iterable: Iterable): B;
-
-function reduce(
- f: (a: A, b: A) => A,
- iterable: AsyncIterable,
-): Promise;
-
-function reduce(
- f: (a: B, b: A) => B | Promise,
- seed: B | Promise,
- iterable: AsyncIterable,
-): Promise;
-
-function reduce(
- f: (a: B, b: A) => B | Promise,
- iterable: AsyncIterable,
-): Promise;
-
-function reduce | AsyncIterable>(
+function reduce(
+ f: Arrow,
+ seed: Acc,
+ iterable: T,
+): Acc;
+
+function reduce(f: (acc: T, value: T) => T, iterable: Iterable): T;
+
+function reduce(
+ f: (acc: Acc, value: T) => Acc,
+ iterable: Iterable,
+): Acc;
+
+function reduce(
+ f: (acc: Acc, value: T) => Acc,
+ seed: Acc,
+ iterable: Iterable,
+): Acc;
+
+function reduce(
+ f: (acc: T, value: T) => T,
+ iterable: AsyncIterable,
+): Promise;
+
+function reduce(
+ f: (acc: Acc, value: T) => Acc | Promise,
+ seed: Acc | Promise,
+ iterable: AsyncIterable,
+): Promise;
+
+function reduce(
+ f: (acc: Acc, value: T) => Acc | Promise,
+ iterable: AsyncIterable,
+): Promise;
+
+function reduce | AsyncIterable>(
f: (
- a: IterableInfer,
- b: IterableInfer,
- ) => IterableInfer | Promise>,
-): (iterable: A) => ReturnValueType>;
-
-function reduce | AsyncIterable, B>(
- f: (a: B, b: IterableInfer) => B | Promise,
-): (iterable: A) => ReturnValueType;
-
-function reduce | AsyncIterable, B>(
- f: (a: B, b: IterableInfer) => B,
- seed?: B | Iterable> | AsyncIterable>,
- iterable?: Iterable> | AsyncIterable>,
-): B | Promise | ((iterable: A) => ReturnValueType) {
+ acc: IterableInfer,
+ value: IterableInfer,
+ ) => IterableInfer | Promise>,
+): (iterable: T) => ReturnValueType>;
+
+function reduce | AsyncIterable, Acc>(
+ f: (acc: Acc, value: IterableInfer) => Acc | Promise,
+): (iterable: T) => ReturnValueType;
+
+function reduce | AsyncIterable, Acc>(
+ f: (acc: Acc, value: IterableInfer) => Acc,
+ seed?: Acc | Iterable> | AsyncIterable>,
+ iterable?: Iterable> | AsyncIterable>,
+): Acc | Promise | ((iterable: T) => ReturnValueType) {
if (iterable === undefined) {
if (seed === undefined) {
- return (iterable: A) =>
- reduce(f, iterable as any) as ReturnValueType;
+ return (iterable: T) =>
+ reduce(f, iterable as any) as ReturnValueType;
}
if (isIterable(seed)) {
@@ -124,7 +171,7 @@ function reduce | AsyncIterable, B>(
if (done) {
throw new TypeError("'reduce' of empty iterable with no initial value");
}
- return sync(f, value as B, {
+ return sync(f, value as Acc, {
[Symbol.iterator]() {
return iterator;
},
@@ -140,7 +187,7 @@ function reduce | AsyncIterable, B>(
);
}
- return async(f, value as Promise, {
+ return async(f, value as Promise, {
[Symbol.asyncIterator]() {
return iterator;
},
@@ -152,11 +199,11 @@ function reduce | AsyncIterable, B>(
}
if (isIterable(iterable)) {
- return sync(f, seed as B, iterable);
+ return sync(f, seed as Acc, iterable);
}
if (isAsyncIterable(iterable)) {
- return async(f, Promise.resolve(seed as B), iterable);
+ return async(f, Promise.resolve(seed as Acc), iterable);
}
throw new TypeError("'iterable' must be type of Iterable or AsyncIterable");