Repository: marpple/FxTS
Pull request #40 (2021-12-05 02:49:57)

Adjust 'timeout' number appropriately
Our tests fail intermittently. https://github.com/marpple/FxTS/pull/39

There are 'timeout' related issues with `jest`, which may not be ours.

https://github.com/facebook/jest/issues?q=is%3Aissue+is%3Aopen+timeout+

If the problem continues, we need to look into it.


Patch:
diff --git a/src/Lazy/index.ts b/src/Lazy/index.ts
index 1071ec26..994b5738 100644
--- a/src/Lazy/index.ts
+++ b/src/Lazy/index.ts
@@ -23,6 +23,7 @@ import toAsync from "./toAsync";
 import uniq from "./uniq";
 import uniqBy from "./uniqBy";
 import zip from "./zip";
+import zipWith from "./zipWith";
 import zipWithIndex from "./zipWithIndex";
 
 export {
@@ -51,5 +52,6 @@ export {
   uniq,
   uniqBy,
   zip,
+  zipWith,
   zipWithIndex,
 };
diff --git a/src/Lazy/zipWith.ts b/src/Lazy/zipWith.ts
new file mode 100644
index 00000000..a730a0f1
--- /dev/null
+++ b/src/Lazy/zipWith.ts
@@ -0,0 +1,61 @@
+import { map, zip } from ".";
+import { isAsyncIterable, isIterable } from "../_internal/utils";
+
+/**
+ * Returns Iterable/AsyncIterable out of the two supplied by applying `f` to each same positioned pair in Iterable/AsyncIterable.
+ *
+ * @example
+ * const iter = zipWith((a,b) => [a,b], [1,2,3], ['a','b','c']);
+ * iter.next(); // {value: [1, 'a'] , done: false}
+ * iter.next(); // {value: [2, 'b'] , done: false}
+ * iter.next(); // {value: [3, 'c'] , done: false}
+ * iter.next(); // {value: undefined , done: true}
+ */
+function zipWith<A, B, C>(
+  f: (a: A, b: B) => C,
+  iterable1: Iterable<A>,
+  iterable2: Iterable<B>,
+): IterableIterator<C>;
+
+function zipWith<A, B, C>(
+  f: (a: A, b: B) => C,
+  iterable1: Iterable<A>,
+  iterable2: AsyncIterable<B>,
+): AsyncIterableIterator<C>;
+
+function zipWith<A, B, C>(
+  f: (a: A, b: B) => C,
+  iterable1: AsyncIterable<A>,
+  iterable2: Iterable<B>,
+): AsyncIterableIterator<C>;
+
+function zipWith<A, B, C>(
+  f: (a: A, b: B) => C,
+  iterable1: AsyncIterable<A>,
+  iterable2: AsyncIterable<B>,
+): AsyncIterableIterator<C>;
+
+function zipWith<A, B, C>(
+  f: (a: A, b: B) => C,
+  iterable1: Iterable<A> | AsyncIterable<A>,
+  iterable2: Iterable<B> | AsyncIterable<B>,
+): IterableIterator<C> | AsyncIterableIterator<C> {
+  if (isIterable(iterable1) && isIterable(iterable2)) {
+    return map(([a, b]) => f(a, b), zip(iterable1, iterable2));
+  }
+  if (isIterable(iterable1) && isAsyncIterable(iterable2)) {
+    return map(([a, b]) => f(a, b), zip(iterable1, iterable2));
+  }
+  if (isAsyncIterable(iterable1) && isIterable(iterable2)) {
+    return map(([a, b]) => f(a, b), zip(iterable1, iterable2));
+  }
+  if (isAsyncIterable(iterable1) && isAsyncIterable(iterable2)) {
+    return map(([a, b]) => f(a, b), zip(iterable1, iterable2));
+  }
+
+  throw new TypeError(
+    "'iterable1' and 'iterable2' must be type of Iterable or AsyncIterable",
+  );
+}
+
+export default zipWith;
diff --git a/src/curry.ts b/src/curry.ts
new file mode 100644
index 00000000..1dfc8323
--- /dev/null
+++ b/src/curry.ts
@@ -0,0 +1,32 @@
+import Curry from "./types/Curry";
+
+/**
+ * Returns a curried function of `f`
+ *
+ * @example
+ * ```ts
+ * const add = (a: number, b: number): number => a + b
+ *
+ * const curried = curry(add)
+ * const add10 = curried(10)
+ * console.log(add10(5)) // 15
+ * console.log(curried(3, 4)) // 7
+ * ```
+ */
+
+function curry<F extends (...args: any[]) => any>(f: F): Curry<F> {
+  const arity = f.length;
+
+  return (function resolver(...args: unknown[]) {
+    const memory = [...args];
+
+    return function (...innerArgs: unknown[]) {
+      const local = [...memory, ...innerArgs];
+      const next = local.length >= arity ? f : resolver;
+
+      return next(...local);
+    };
+  })() as any;
+}
+
+export default curry;
diff --git a/src/index.ts b/src/index.ts
index f0f62157..59672750 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,5 @@
 import countBy from "./countBy";
+import curry from "./curry";
 import delay from "./delay";
 import each from "./each";
 import every from "./every";
@@ -24,6 +25,7 @@ import toArray from "./toArray";
 
 export {
   countBy,
+  curry,
   delay,
   each,
   every,
diff --git a/src/types/Curry.ts b/src/types/Curry.ts
new file mode 100644
index 00000000..8c55fc47
--- /dev/null
+++ b/src/types/Curry.ts
@@ -0,0 +1,19 @@
+import Length from "./Length";
+import Cast from "./Cast";
+import Drop from "./Drop";
+
+type CleanGaps<O extends any[]> = {
+  [K in keyof O]: NonNullable<O[K]>;
+};
+
+type Gaps<L extends any[]> = Cast<CleanGaps<{ [K in keyof L]?: L[K] }>, any[]>;
+
+type Curry<F extends (...args: any[]) => any> = <
+  T extends any[],
+  G = Drop<Length<T>, Parameters<F>>,
+  R = ReturnType<F>,
+>(
+  ...args: Cast<T, Gaps<Parameters<F>>>
+) => G extends [any, ...any[]] ? Curry<(...args: G) => R> : R;
+
+export default Curry;
diff --git a/src/types/Prepend.ts b/src/types/Prepend.ts
index a36b248f..bacb9ef1 100644
--- a/src/types/Prepend.ts
+++ b/src/types/Prepend.ts
@@ -1,3 +1,3 @@
-type Prepend<ARR extends any[], T> = [T, ...ARR];
+type Prepend<ARR extends unknown[], T> = [T, ...ARR];
 
 export default Prepend;


Test patch:
diff --git a/test/Lazy/dropUntil.spec.ts b/test/Lazy/dropUntil.spec.ts
index a458d859..0e11ea72 100644
--- a/test/Lazy/dropUntil.spec.ts
+++ b/test/Lazy/dropUntil.spec.ts
@@ -90,11 +90,11 @@ describe("dropUntil", function () {
 
     it("should be dropped elements concurrently", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 300);
+      callFuncAfterTime(fn, 1500);
       const res = await pipe(
         [1, 2, 3, 4, 5, 1, 2],
         toAsync,
-        map((a) => delay(100, a + 10)),
+        map((a) => delay(500, a + 10)),
         filter((a) => a % 2 === 1),
         dropUntil((a) => a > 13),
         concurrent(3),
@@ -102,25 +102,25 @@ describe("dropUntil", function () {
       );
       expect(fn).toBeCalled();
       expect(res).toEqual([11]);
-    }, 350);
+    }, 1550);
 
     it("should be controlled the order when concurrency", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 1000);
+      callFuncAfterTime(fn, 2000);
 
       const res = await pipe(
         toAsync(
           (function* () {
-            yield delay(500, 1);
-            yield delay(400, 2);
-            yield delay(300, 3);
-            yield delay(200, 4);
-            yield delay(100, 5);
-            yield delay(500, 11);
-            yield delay(400, 12);
-            yield delay(300, 13);
-            yield delay(200, 8);
-            yield delay(100, 9);
+            yield delay(1000, 1);
+            yield delay(900, 2);
+            yield delay(800, 3);
+            yield delay(700, 4);
+            yield delay(600, 5);
+            yield delay(1000, 11);
+            yield delay(900, 12);
+            yield delay(800, 13);
+            yield delay(700, 8);
+            yield delay(600, 9);
           })(),
         ),
         dropUntil((a) => a > 12),
@@ -129,7 +129,7 @@ describe("dropUntil", function () {
       );
       expect(fn).toBeCalled();
       expect(res).toEqual([8, 9]);
-    }, 1050);
+    }, 2050);
 
     it("should be able to handle an error when working concurrent", async function () {
       await expect(
diff --git a/test/Lazy/dropWhile.spec.ts b/test/Lazy/dropWhile.spec.ts
index a878bdd4..3fb88263 100644
--- a/test/Lazy/dropWhile.spec.ts
+++ b/test/Lazy/dropWhile.spec.ts
@@ -93,21 +93,21 @@ describe("dropWhile", function () {
 
     it("should be controlled the order when concurrency", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 1000);
+      callFuncAfterTime(fn, 2000);
 
       const res = await pipe(
         toAsync(
           (function* () {
-            yield delay(500, 1);
-            yield delay(400, 2);
-            yield delay(300, 3);
-            yield delay(200, 4);
-            yield delay(100, 5);
-            yield delay(500, 6);
-            yield delay(400, 7);
-            yield delay(300, 8);
-            yield delay(200, 1);
-            yield delay(100, 10);
+            yield delay(1000, 1);
+            yield delay(900, 2);
+            yield delay(800, 3);
+            yield delay(700, 4);
+            yield delay(600, 5);
+            yield delay(1000, 6);
+            yield delay(900, 7);
+            yield delay(800, 8);
+            yield delay(700, 1);
+            yield delay(600, 10);
           })(),
         ),
         dropWhile((a) => a < 7),
@@ -116,7 +116,7 @@ describe("dropWhile", function () {
       );
       expect(fn).toBeCalled();
       expect(res).toEqual([7, 8, 1, 10]);
-    }, 1050);
+    }, 2050);
 
     it("should be able to handle an error when working concurrent", async function () {
       await expect(
diff --git a/test/Lazy/filter.spec.ts b/test/Lazy/filter.spec.ts
index e0ed0e9d..822687d5 100644
--- a/test/Lazy/filter.spec.ts
+++ b/test/Lazy/filter.spec.ts
@@ -194,11 +194,11 @@ describe("filter", function () {
 
     it("should be filtered by the callback 'filter' - 'take' - 'concurrent'", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 2000);
+      callFuncAfterTime(fn, 1000);
 
       const res = await pipe(
         toAsync(range(1, 51)),
-        filter((a) => delay(1000, a % 2 === 0)),
+        filter((a) => delay(500, a % 2 === 0)),
         take(10),
         concurrent(10),
         toArray,
@@ -206,15 +206,15 @@ describe("filter", function () {
 
       expect(fn).toBeCalled();
       expect(res).toEqual([2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
-    }, 2050);
+    }, 1050);
 
     it("should be filtered by the callback 'map' - 'filter' - 'concurrent'", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 2000);
+      callFuncAfterTime(fn, 1000);
 
       const res = await pipe(
         toAsync(range(1, 21)),
-        map((a) => delay(1000, a + 10)),
+        map((a) => delay(500, a + 10)),
         filter((a) => a % 2 === 0),
         concurrent(10),
         toArray,
@@ -222,15 +222,15 @@ describe("filter", function () {
 
       expect(fn).toBeCalled();
       expect(res).toEqual([12, 14, 16, 18, 20, 22, 24, 26, 28, 30]);
-    }, 2050);
+    }, 1050);
 
     it("should be filtered by the callback 'map' - 'filter' - 'concurrent' - 'take'", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 200);
+      callFuncAfterTime(fn, 1000);
 
       const res = await pipe(
         toAsync(range(1, 10)),
-        map((a) => delay(100, a)),
+        map((a) => delay(500, a)),
         filter((a) => a),
         concurrent(5),
         take(8),
@@ -239,13 +239,13 @@ describe("filter", function () {
 
       expect(fn).toBeCalled();
       expect(res).toEqual([...range(1, 9)]);
-    }, 210);
+    }, 1050);
 
     it("should be able to handle an error when the callback is asynchronous", async function () {
       await expect(
         pipe(
           toAsync(range(1, 1000)),
-          map((a) => delay(100, a + 10)),
+          map((a) => delay(500, a + 10)),
           filter((a) => {
             if (a === 14) {
               throw new Error("err");
@@ -256,7 +256,7 @@ describe("filter", function () {
           toArray,
         ),
       ).rejects.toThrow("err");
-    }, 250);
+    }, 1050);
 
     it("should be able to handle errors when the callback is asynchronous", async function () {
       await expect(
@@ -285,11 +285,11 @@ describe("filter", function () {
 
     it("should be consumed 'AsyncIterable' as many times as called with 'next'", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 4000);
+      callFuncAfterTime(fn, 2000);
       const iterator = toAsync(range(1, 21));
       const res = pipe(
         iterator,
-        map((a) => delay(1000, a)),
+        map((a) => delay(500, a)),
         filter((a) => a % 2 === 0),
         concurrent(3),
       );
@@ -308,7 +308,7 @@ describe("filter", function () {
 
       const { value: v6 } = await iterator.next();
       expect(v6).toEqual(13);
-    }, 4050);
+    }, 2050);
 
     it("should be passed concurrent object when job works concurrently", async function () {
       const mock = generatorMock();
diff --git a/test/Lazy/flat.spec.ts b/test/Lazy/flat.spec.ts
index 5ebe8732..94f59d0a 100644
--- a/test/Lazy/flat.spec.ts
+++ b/test/Lazy/flat.spec.ts
@@ -66,7 +66,7 @@ describe("flat", function () {
 
     it("should be flattened concurrently", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 2000);
+      callFuncAfterTime(fn, 1000);
       const iterator = toAsync([
         [1],
         [2],
@@ -82,7 +82,7 @@ describe("flat", function () {
 
       const res = pipe(
         iterator,
-        map((a) => delay(1000, a)),
+        map((a) => delay(500, a)),
         flat,
         concurrent(3),
       );
@@ -103,7 +103,7 @@ describe("flat", function () {
 
       const { value: v7 } = await iterator.next();
       expect(v7).toEqual([13]);
-    }, 2050);
+    }, 1050);
 
     type FlatTest = {
       input: Array<any>;
@@ -123,7 +123,7 @@ describe("flat", function () {
         ],
         depth: 1,
         size: 1,
-        timeout: 2000,
+        timeout: 1000,
         expected: [1, 2, 3, 4, 5, 6, 7, 8],
       },
       {
@@ -135,7 +135,7 @@ describe("flat", function () {
         ],
         depth: 1,
         size: 3,
-        timeout: 2000,
+        timeout: 1000,
         expected: [1, 2, 3, 4, 5, 6, 7, 8],
       },
       {
@@ -147,7 +147,7 @@ describe("flat", function () {
         ],
         depth: 1,
         size: 4,
-        timeout: 1000,
+        timeout: 500,
         expected: [1, 2, 3, 4, 5, 6, 7, 8],
       },
       {
@@ -159,7 +159,7 @@ describe("flat", function () {
         ],
         depth: 1,
         size: 4,
-        timeout: 1000,
+        timeout: 500,
         expected: [1, [2], 3, [4], 5, [6], 7, [8]],
       },
       {
@@ -171,94 +171,54 @@ describe("flat", function () {
         ],
         depth: 2,
         size: 4,
-        timeout: 1000,
+        timeout: 500,
         expected: [1, 2, 3, 4, 5, 6, 7, 8],
       },
       {
-        input: [
-          [1], //
-          [2, 3],
-          [4],
-          [5, 6],
-          [7],
-          [8, 9],
-        ],
+        input: [[1], [2, 3], [4], [5, 6], [7], [8, 9]],
         depth: 1,
         size: 2,
-        timeout: 3000,
+        timeout: 1500,
         expected: [1, 2, 3, 4, 5, 6, 7, 8, 9],
       },
       {
-        input: [
-          [1], //
-          [2, 3],
-          [4],
-          [5, 6],
-          [7],
-          [8, 9],
-          [10],
-        ],
+        input: [[1], [2, 3], [4], [5, 6], [7], [8, 9], [10]],
         depth: 1,
         size: 2,
-        timeout: 4000,
+        timeout: 2000,
         expected: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
       },
       {
-        input: [
-          [1], //
-          [2, 3],
-          [4],
-          [5, 6],
-          [7],
-          [8, 9],
-        ],
+        input: [[1], [2, 3], [4], [5, 6], [7], [8, 9]],
         depth: 1,
         size: 3,
-        timeout: 2000,
+        timeout: 1000,
         expected: [1, 2, 3, 4, 5, 6, 7, 8, 9],
       },
       {
-        input: [
-          [1], //
-          [2, 3, 4],
-          [5, 6],
-          [7, 8, 9, 10],
-          [11, 12],
-        ],
+        input: [[1], [2, 3, 4], [5, 6], [7, 8, 9, 10], [11, 12]],
         depth: 1,
         size: 3,
-        timeout: 2000,
+        timeout: 1000,
         expected: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
       },
       {
-        input: [
-          [1], //
-          [2, 3, 4],
-          [5, 6],
-          [7, 8, 9, 10],
-          [11, 12],
-        ],
+        input: [[1], [2, 3, 4], [5, 6], [7, 8, 9, 10], [11, 12]],
         depth: 1,
         size: 3,
-        timeout: 2000,
+        timeout: 1000,
         expected: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
       },
       {
-        input: [
-          [1], //
-          [[[2]], 3, 4],
-          [5, [[[6]]]],
-          [7, 8, 9, 10],
-          [11, 12],
-        ],
+        input: [[1], [[[2]], 3, 4], [5, [[[6]]]], [7, 8, 9, 10], [11, 12]],
         depth: 2,
         size: 3,
-        timeout: 2000,
+        timeout: 1000,
         expected: [1, [2], 3, 4, 5, [[6]], 7, 8, 9, 10, 11, 12],
       },
       {
         input: [
-          [1], //
+          [1],
           [[[2]], 3, [[[[4]]]]],
           [5, [[[6]]]],
           [7, 8, 9, 10],
@@ -266,13 +226,13 @@ describe("flat", function () {
         ],
         depth: 2,
         size: 5,
-        timeout: 1000,
+        timeout: 500,
         expected: [1, [2], 3, [[[4]]], 5, [[6]], 7, 8, 9, 10, 11, 12],
       },
     ];
 
     it.each(testParameters)(
-      `should be flattened concurrently`,
+      "should be flattened concurrently",
       async ({ timeout, input, depth, size, expected }: FlatTest) => {
         const fn = jest.fn();
         jest.setTimeout(timeout + 100);
@@ -280,7 +240,7 @@ describe("flat", function () {
 
         const res = await pipe(
           toAsync(input),
-          map((a) => delay(1000, a)),
+          map((a) => delay(500, a)),
           (a) => flat(a, depth),
           concurrent(size),
           toArray,
@@ -293,11 +253,11 @@ describe("flat", function () {
 
     it("should be flattened concurrently with chuck", async function () {
       const fn = jest.fn();
-      callFuncAfterTime(fn, 2000);
+      callFuncAfterTime(fn, 1000);
 
       const res = await pipe(
         toAsync(range(1, 7)),
-        map((a) => delay(1000, a)),
+        map((a) => delay(500, a)),
         chunk(2),
         flat,
         concurrent(3),
@@ -306,7 +266,7 @@ describe("flat", function () {
 
       expect(fn).toBeCalled();
       expect(res).toEqual([1, 2, 3, 4, 5, 6]);
-    }, 2050);
+    }, 1050);
 
     it("should be flattened concurrently with filter", async function () {
       const res = await pipe(
diff --git a/test/Lazy/zipWith.spec.ts b/test/Lazy/zipWith.spec.ts
new file mode 100644
index 00000000..726de3a1
--- /dev/null
+++ b/test/Lazy/zipWith.spec.ts
@@ -0,0 +1,57 @@
+import { toAsync } from "../../src";
+import zipWith from "../../src/Lazy/zipWith";
+
+describe("zipWith", function () {
+  const iter1 = ["foo", "bar", "ha"];
+  const iter2 = [1, 2, 3];
+  const then = [{ foo: 1 }, { bar: 2 }, { ha: 3 }];
+
+  describe("sync", function () {
+    it("should apply `f` to each same positioned pair", function () {
+      const acc = [];
+      const iter = zipWith((a, b) => ({ [a]: b }), iter1, iter2);
+      for (const a of iter) {
+        acc.push(a);
+      }
+      expect(acc).toEqual(then);
+    });
+  });
+
+  describe("async", function () {
+    it("should apply `f` to each same positioned pair [iterable/AsyncIterable]", async function () {
+      const acc = [];
+      const iter = zipWith((a, b) => ({ [a]: b }), toAsync(iter1), iter2);
+      for await (const a of iter) {
+        acc.push(a);
+      }
+
+      expect(acc).toEqual(then);
+    });
+
+    it("should apply `f` to each same positioned pair [AsyncIterable/iterable]", async function () {
+      const acc = [];
+      const iter = zipWith((a, b) => ({ [a]: b }), toAsync(iter1), iter2);
+
+      for await (const a of iter) {
+        acc.push(a);
+      }
+
+      expect(acc).toEqual(then);
+    });
+
+    it("should apply `f` to each same positioned pair [AsyncIterable/AsyncIterable]", async function () {
+      const acc = [];
+      const iter = zipWith(
+        (a, b) => ({ [a]: b }),
+        toAsync(iter1),
+        toAsync(iter2),
+      );
+
+      for await (const a of iter) {
+        acc.push(a);
+      }
+
+      expect(acc).toEqual(then);
+    });
+  });
+});
diff --git a/test/curry.spec.ts b/test/curry.spec.ts
new file mode 100644
index 00000000..3e4578d3
--- /dev/null
+++ b/test/curry.spec.ts
@@ -0,0 +1,20 @@
+import { curry } from "../src";
+
+describe("curry", function () {
+  it("should not change a unary function", function () {
+    const unary = (a: string) => a + "bar";
+    const curried = curry(unary);
+    expect(curried("foo")).toBe("foobar");
+  });
+
+  it("given function should be curried", function () {
+    const add = (a: number, b: number, c: number) => a + b + c;
+    const curried = curry(add);
+    expect(curried(1)(2)(3)).toBe(6);
+    expect(curried(1, 2)(3)).toBe(6);
+    expect(curried(1)(2, 3)).toBe(6);
+    expect(curried(1, 2, 3)).toBe(6);
+    expect(curried()(1, 2, 3)).toBe(6);
+    expect(curried(1)()(2, 3)).toBe(6);
+  });
+});
diff --git a/type-check/Lazy/zipWith.test.ts b/type-check/Lazy/zipWith.test.ts
new file mode 100644
index 00000000..d19235a0
--- /dev/null
+++ b/type-check/Lazy/zipWith.test.ts
@@ -0,0 +1,47 @@
+import * as Test from "../../src/types/Test";
+import { toAsync, zipWith } from "../../src";
+
+const { checks, check } = Test;
+
+const iter1 = ["foo", "bar", "ha"];
+const iter2 = [1, 2, 3];
+
+const res1 = zipWith((a, b) => ({ [a]: b }), iter1, iter2);
+const res2 = zipWith((a, b) => ({ [a]: b }), toAsync(iter1), iter2);
+const res3 = zipWith((a, b) => ({ [a]: b }), iter1, toAsync(iter2));
+const res4 = zipWith((a, b) => ({ [a]: b }), toAsync(iter1), toAsync(iter2));
+const res5 = zipWith((a, b) => [a, b], iter1, iter2);
+const res6 = zipWith((a, b) => [a, b] as [string, number], iter1, iter2);
+
+checks([
+  check<
+    typeof res1,
+    IterableIterator<{
+      [x: string]: number;
+    }>,
+    Test.Pass
+  >(),
+  check<
+    typeof res2,
+    AsyncIterableIterator<{
+      [x: string]: number;
+    }>,
+    Test.Pass
+  >(),
+  check<
+    typeof res3,
+    AsyncIterableIterator<{
+      [x: string]: number;
+    }>,
+    Test.Pass
+  >(),
+  check<
+    typeof res4,
+    AsyncIterableIterator<{
+      [x: string]: number;
+    }>,
+    Test.Pass
+  >(),
+  check<typeof res5, IterableIterator<(string | number)[]>, Test.Pass>(),
+  check<typeof res6, IterableIterator<[string, number]>, Test.Pass>(),
+]);
diff --git a/type-check/curry.test.ts b/type-check/curry.test.ts
new file mode 100644
index 00000000..3fac72c9
--- /dev/null
+++ b/type-check/curry.test.ts
@@ -0,0 +1,37 @@
+import * as Test from "../src/types/Test";
+import Curry from "../src/types/Curry";
+import { curry, pipe, toAsync } from "../src";
+import { filter } from "../src/Lazy";
+
+const { checks, check } = Test;
+
+declare function fn(a: string, c: boolean, ...d: number[]): string;
+
+declare const curried: Curry<typeof fn>;
+
+const res1 = curried("a");
+const res2 = res1();
+const res3 = res2(true);
+const res4 = res2(false, 1, 2, 3);
+
+const strictEq = curry(<T>(left: T, right: T) => left === right);
+
+const res5 = pipe([1, 1, 1, 2, 2, 2], filter(strictEq(2)));
+const res6 = pipe([1, 1, 1, 2, 2, 2], toAsync, filter(strictEq(2)));
+
+checks([
+  check<
+    typeof res1,
+    Curry<(c: boolean, ...d: number[]) => string>,
+    Test.Pass
+  >(),
+  check<
+    typeof res2,
+    Curry<(c: boolean, ...d: number[]) => string>,
+    Test.Pass
+  >(),
+  check<typeof res3, string, Test.Pass>(),
+  check<typeof res4, string, Test.Pass>(),
+  check<typeof res5, IterableIterator<number>, Test.Pass>(),
+  check<typeof res6, AsyncIterableIterator<number>, Test.Pass>(),
+]);
diff --git a/type-check/types/Length.test.ts b/type-check/types/Length.test.ts
index 0663f2f0..e258541a 100644
--- a/type-check/types/Length.test.ts
+++ b/type-check/types/Length.test.ts
@@ -6,4 +6,5 @@ const { checks, check } = Test;
 checks([
   check<Length<[]>, 0, Test.Pass>(),
   check<Length<[1, 2, 3, 4]>, 4, Test.Pass>(),
+  check<Length<[1, 2, 3, 4, ...number[]]>, number, Test.Pass>(),
 ]);
diff --git a/type-check/types/Prepend.test.ts b/type-check/types/Prepend.test.ts
new file mode 100644
index 00000000..10502726
--- /dev/null
+++ b/type-check/types/Prepend.test.ts
@@ -0,0 +1,9 @@
+import * as Test from "../../src/types/Test";
+import Prepend from "../../src/types/Prepend";
+
+const { checks, check } = Test;
+
+checks([
+  check<Prepend<[], number>, [number], Test.Pass>(),
+  check<Prepend<[1, true], string>, [string, 1, true], Test.Pass>(),
+]);