Skip to content

Commit

Permalink
each
Browse files Browse the repository at this point in the history
  • Loading branch information
uriva committed Jun 30, 2024
1 parent 4e4e76d commit 8bcd01f
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 14 deletions.
13 changes: 6 additions & 7 deletions src/composition.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { reverse } from "./array.ts";
import { not } from "./operator.ts";
import { isPromise } from "./promise.ts";
import { reduce } from "./reduce.ts";
import { currentLocation } from "./trace.ts";
import {
AnyAsync,
AsyncFunction,
Func,
Last,
ParamOf,
ReturnTypeUnwrapped,
UnaryFnUntyped,
} from "./typing.ts";

import { not } from "./operator.ts";
import { reduce } from "./reduce.ts";
import { currentLocation } from "./trace.ts";
import { isPromise } from "./promise.ts";

type UnaryFn<A, R> = (a: A) => R;
// deno-lint-ignore no-explicit-any
type UnaryFnUntyped = (a: any) => any;

// deno-lint-ignore no-explicit-any
type Res<F> = F extends UnaryFn<any, infer R> ? R : never;

Expand Down
27 changes: 26 additions & 1 deletion src/map.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { map, mapCat } from "./map.ts";
import { each, map, mapCat } from "./map.ts";

import { assertEquals } from "std-assert";
import { wrapPromise } from "./promise.ts";
Expand All @@ -18,6 +18,31 @@ import { wrapPromise } from "./promise.ts";
});
});

[
[1, 2, 3],
[],
].forEach((it, i) => {
Deno.test(`each with iterable ${i}`, () => {
const results: number[] = [];
each((input: number) => results.push(input))(it);
assertEquals(results, it);
});
});

[
[1, 2, 3],
[],
].forEach((it, i) => {
Deno.test(`each async with iterable ${i}`, async () => {
const results: number[] = [];
await each((input: number): Promise<void> => {
results.push(input);
return Promise.resolve();
})(it);
assertEquals(results, it);
});
});

Deno.test("map doesn't include indices", () => {
assertEquals(map(parseInt)(["4", "3", "7"]), [4, 3, 7]);
});
Expand Down
23 changes: 17 additions & 6 deletions src/map.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { AsyncFunction, Unary } from "./typing.ts";
import { AsyncFunction, Unary, UnaryFnUntyped } from "./typing.ts";

import { pipe } from "./composition.ts";
import { reduce } from "./reduce.ts";
import { isPromise } from "./promise.ts";

// deno-lint-ignore no-explicit-any
export const map = <Function extends (_: any) => any>(f: Function) =>
export const map = <F extends UnaryFnUntyped>(f: F) =>
(
xs: Parameters<Function>[0][],
): Function extends AsyncFunction ? Promise<Awaited<ReturnType<Function>>[]>
: ReturnType<Function>[] => {
xs: Parameters<F>[0][],
): F extends AsyncFunction ? Promise<Awaited<ReturnType<F>>[]>
: ReturnType<F>[] => {
const results = [];
for (const x of xs) {
results.push(f(x));
Expand All @@ -18,6 +17,18 @@ export const map = <Function extends (_: any) => any>(f: Function) =>
return results.some(isPromise) ? Promise.all(results) : results;
};

export const each = <F extends UnaryFnUntyped>(f: F) =>
// @ts-expect-error ts cannot reason about this
(xs: Parameters<F>[0][]): F extends AsyncFunction ? Promise<void> : void => {
const results = [];
for (const x of xs) {
const result = f(x);
if (isPromise(result)) results.push(result);
}
// @ts-expect-error ts cannot reason about this dynamic ternary
if (results.length) return Promise.all(results).then();
};

export const mapCat = <T, G>(
f: Unary<T, G>,
) =>
Expand Down
3 changes: 3 additions & 0 deletions src/typing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ export type Reducer<T, S> = (state: S, element: T) => S;
export type ReturnTypeUnwrapped<F extends Func> = F extends AsyncFunction
? Awaited<ReturnType<F>>
: ReturnType<F>;

// deno-lint-ignore no-explicit-any
export type UnaryFnUntyped = (input: any) => any;

0 comments on commit 8bcd01f

Please sign in to comment.