Repository: marpple/FxTS
Pull request #220 (2023-07-19 19:59:56)

feat: pipeLazy (#218)

ppeeou: @darky Thank you for your contribution
sorry for the late confirmation

I left a comment
In the following situation, function inference is wrong
Is it possible to implement a function to be inferred as a 'Promise' ?

```ts
const res = pipeLazy((a: number) => String(a))(Promise.resolve(2));
// infer res -> String not Promise(String)
```

darky: > I left a comment In the following situation, function inference is wrong Is it possible to implement a function to be inferred as a 'Promise' ?
> 
> ```ts
> const res = pipeLazy((a: number) => String(a))(Promise.resolve(2));
> // infer res -> String not Promise(String)
> ```

@ppeeou fixed

Patch:
diff --git a/src/Lazy/index.ts b/src/Lazy/index.ts
index bf5919a7..222cb7f0 100644
--- a/src/Lazy/index.ts
+++ b/src/Lazy/index.ts
@@ -20,6 +20,7 @@ import intersectionBy from "./intersectionBy";
 import keys from "./keys";
 import map from "./map";
 import peek from "./peek";
+import pipeLazy from "./pipeLazy";
 import pluck from "./pluck";
 import prepend from "./prepend";
 import range from "./range";
@@ -64,6 +65,7 @@ export {
   keys,
   map,
   peek,
+  pipeLazy,
   pluck,
   prepend,
   range,
diff --git a/src/Lazy/pipeLazy.ts b/src/Lazy/pipeLazy.ts
new file mode 100644
index 00000000..eb1945c1
--- /dev/null
+++ b/src/Lazy/pipeLazy.ts
@@ -0,0 +1,382 @@
+import pipe1 from "../pipe1";
+import reduce from "../reduce";
+import type Awaited from "../types/Awaited";
+import type ReturnPipeType from "../types/ReturnPipeType";
+
+/**
+ * Make function, that performs left to right function composition.
+ * All arguments must be unary.
+ *
+ * @example
+ * ```ts
+ * pipeLazy(
+ *  map(a => a + 10),
+ *  filter(a => a % 2 === 0),
+ *  toArray,
+ * )([1, 2, 3, 4, 5]); // [12, 14]
+ *
+ * await pipeLazy(
+ *  map(a => a + 10),
+ *  filter(a => a % 2 === 0),
+ *  toArray,
+ * )(Promise.resolve([1, 2, 3, 4, 5])); // [12, 14]
+ *
+ * // if you want to use asynchronous callback
+ * await pipeLazy(
+ *  toAsync,
+ *  map(async (a) => a + 10),
+ *  filter((a) => a % 2 === 0),
+ *  toArray,
+ * )(Promise.resolve([1, 2, 3, 4, 5])); // [12, 14]
+ *
+ * // with toAsync
+ * await pipeLazy(
+ *  toAsync,
+ *  map(a => a + 10),
+ *  filter(a => a % 2 === 0),
+ *  toArray,
+ * )([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), Promise.resolve(4), Promise.resolve(5)]); // [12, 14]
+ * ```
+ *
+ * {@link https://codesandbox.io/s/fxts-toarray-fy84i | Try It}
+ *
+ * see {@link https://fxts.dev/docs/pipeLazy | pipeLazy}, {@link https://fxts.dev/docs/toAsync | toAsync},
+ * {@link https://fxts.dev/docs/map | map}, {@link https://fxts.dev/docs/filter | filter}
+ */
+// eslint-disable-next-line
+// @ts-ignore
+// prettier-ignore
+function pipeLazy<T1, R>(
+  f1: (a: Awaited<T1>) => R
+): 
+  & ((a: T1) => ReturnPipeType<[T1,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => R
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => T14,
+  f14: (a: Awaited<T14>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => T14,
+  f14: (a: Awaited<T14>) => T15,
+  f15: (a: Awaited<T15>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => T14,
+  f14: (a: Awaited<T14>) => T15,
+  f15: (a: Awaited<T15>) => T16,
+  f16: (a: Awaited<T16>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => T14,
+  f14: (a: Awaited<T14>) => T15,
+  f15: (a: Awaited<T15>) => T16,
+  f16: (a: Awaited<T16>) => T17,
+  f17: (a: Awaited<T17>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => T14,
+  f14: (a: Awaited<T14>) => T15,
+  f15: (a: Awaited<T15>) => T16,
+  f16: (a: Awaited<T16>) => T17,
+  f17: (a: Awaited<T17>) => T18,
+  f18: (a: Awaited<T18>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => T14,
+  f14: (a: Awaited<T14>) => T15,
+  f15: (a: Awaited<T15>) => T16,
+  f16: (a: Awaited<T16>) => T17,
+  f17: (a: Awaited<T17>) => T18,
+  f18: (a: Awaited<T18>) => T19,
+  f19: (a: Awaited<T19>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,R]>);
+
+// prettier-ignore
+function pipeLazy<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R>(
+  f1: (a: Awaited<T1>) => T2,
+  f2: (a: Awaited<T2>) => T3,
+  f3: (a: Awaited<T3>) => T4,
+  f4: (a: Awaited<T4>) => T5,
+  f5: (a: Awaited<T5>) => T6,
+  f6: (a: Awaited<T6>) => T7,
+  f7: (a: Awaited<T7>) => T8,
+  f8: (a: Awaited<T8>) => T9,
+  f9: (a: Awaited<T9>) => T10,
+  f10: (a: Awaited<T10>) => T11,
+  f11: (a: Awaited<T11>) => T12,
+  f12: (a: Awaited<T12>) => T13,
+  f13: (a: Awaited<T13>) => T14,
+  f14: (a: Awaited<T14>) => T15,
+  f15: (a: Awaited<T15>) => T16,
+  f16: (a: Awaited<T16>) => T17,
+  f17: (a: Awaited<T17>) => T18,
+  f18: (a: Awaited<T18>) => T19,
+  f19: (a: Awaited<T19>) => T20,
+  f20: (a: Awaited<T20>) => R,
+):
+  & ((a: T1) => ReturnPipeType<[T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,R]>)
+  & ((a: Promise<T1>) => ReturnPipeType<[Promise<T1>,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,R]>);
+
+function pipeLazy(...fns: any[]) {
+  return (a: any) => reduce(pipe1, a, fns);
+}
+
+export default pipeLazy;


Test patch:
diff --git a/test/Lazy/pipeLazy.spec.ts b/test/Lazy/pipeLazy.spec.ts
new file mode 100644
index 00000000..adf9a8df
--- /dev/null
+++ b/test/Lazy/pipeLazy.spec.ts
@@ -0,0 +1,94 @@
+import {
+  delay,
+  each,
+  filter,
+  map,
+  pipeLazy,
+  range,
+  reduce,
+  toArray,
+  toAsync,
+} from "../../src";
+
+describe("pipeLazy", function () {
+  describe("sync", function () {
+    it("should return the value evaluated by the composed function", function () {
+      const res = pipeLazy(
+        (n: number) => String(n + 1),
+        (n) => Number(n) + 1,
+        (n) => String(n + 1),
+      )(0);
+      expect(res).toEqual("3");
+    });
+
+    it("should work when the composed function deals with 'Iterable'", function () {
+      const res = pipeLazy(
+        (n: number[]) => map((a) => a + 5, n),
+        (n) => filter((a) => a % 2 === 0, n),
+        (n) => reduce((a, b) => a + b, 0, n),
+      )([1, 2, 3, 4, 5]);
+      expect(res).toEqual(24);
+    });
+  });
+
+  describe("async", function () {
+    it("should work when the composed function deals with 'AsyncIterable'", async function () {
+      const res1 = await pipeLazy(
+        (n: AsyncIterableIterator<number>) => map((a) => a + 5, n),
+        (n) => filter((a) => a % 2 === 0, n),
+        (n) => reduce((a, b) => a + b, 0, n),
+      )(toAsync([1, 2, 3, 4, 5]));
+
+      expect(res1).toEqual(24);
+
+      const res2 = await pipeLazy(
+        (n: AsyncIterableIterator<number>) => map((a) => a + 5, n),
+        (n) => filter((a) => a % 2 === 0, n),
+        (n) => toArray(n),
+        (n) => reduce((a, b) => a + b, 0, n),
+      )(toAsync([1, 2, 3, 4, 5]));
+
+      expect(res2).toEqual(24);
+    });
+
+    it("should return rejected 'Promise' if an error occurs in the callback", async function () {
+      await expect(
+        pipeLazy(
+          (a: AsyncIterableIterator<number>) =>
+            map(() => {
+              throw new Error("err");
+            }, a),
+          (a) => reduce((acc: number, a) => acc + a, a),
+        )(toAsync(range(1, 10))),
+      ).rejects.toThrow("err");
+
+      // Promise reject
+      await expect(
+        pipeLazy(
+          (a: AsyncIterableIterator<number>) =>
+            map(() => Promise.reject(new Error("err")), a),
+          (a) => reduce((acc: number, a) => acc + a, a),
+        )(toAsync(range(1, 10))),
+      ).rejects.toThrow("err");
+    });
+
+    it("should be able to use thenable object", async function () {
+      let res = 0;
+
+      await pipeLazy(
+        (arr: string[]) => arr,
+        toAsync,
+        each(() => {
+          return {
+            then: (resolve: any) => {
+              resolve(delay(0).then(() => res++));
+            },
+            catch: (reject: any) => reject(),
+          };
+        }),
+      )(["a", "b", "c"]);
+
+      expect(res).toBe(3);
+    });
+  });
+});
diff --git a/type-check/Lazy/pipeLazy.test.ts b/type-check/Lazy/pipeLazy.test.ts
new file mode 100644
index 00000000..c84dbe02
--- /dev/null
+++ b/type-check/Lazy/pipeLazy.test.ts
@@ -0,0 +1,86 @@
+import { pipeLazy, throwError } from "../../src";
+import * as Test from "../../src/types/Test";
+
+const { checks, check } = Test;
+
+const res1 = pipeLazy(String)(1);
+const res2 = pipeLazy(Number)("1");
+
+const res3 = pipeLazy(async (n: number) => String(n))(Promise.resolve(1));
+const res4 = pipeLazy(async (s: string) => Number(s))(Promise.resolve("1"));
+
+const res5 = pipeLazy((a) => Promise.resolve(String(a)))(1);
+const res6 = pipeLazy((a) => Promise.resolve(Number(a)))("1");
+
+const res7 = pipeLazy((a) => Promise.resolve(String(a)))(Promise.resolve(1));
+const res8 = pipeLazy((a) => Promise.resolve(Number(a)))(Promise.resolve("1"));
+
+const res9 = pipeLazy(
+  (a: "a" | "b") => a.toUpperCase(),
+  () => 1,
+)("a");
+
+const res10 = pipeLazy(
+  (a: "a") => a.toUpperCase(),
+  async () => 1,
+)(Promise.resolve("a" as const));
+
+const res11 = pipeLazy(
+  (a: "a") => Promise.resolve(a.toUpperCase()),
+  () => 1,
+)(Promise.resolve("a" as const));
+
+const res12 = pipeLazy(
+  (a: "a") => a.toUpperCase(),
+  () => Promise.resolve(1),
+)(Promise.resolve("a" as const));
+
+const res13 = pipeLazy(
+  (a: "a") => (Math.random() > 0.5 ? a.toUpperCase() : Promise.resolve("hi")),
+  () => 1,
+)(Promise.resolve("a" as const));
+
+const res14 = pipeLazy(throwError(() => Error()))(0);
+
+const res15 = pipeLazy(
+  async () => 1,
+  throwError(() => Error()),
+)(0);
+
+const res16 = pipeLazy(
+  throwError(() => Error()),
+  async () => 1,
+  () => 2,
+)(0);
+
+const res17 = pipeLazy(
+  async () => {
+    throw Error("");
+  },
+  throwError(() => Error("")),
+  () => 1,
+  () => 2,
+)(0);
+
+const res18 = pipeLazy((a: number) => String(a))(Promise.resolve(2));
+
+checks([
+  check<typeof res1, string, Test.Pass>(),
+  check<typeof res2, number, Test.Pass>(),
+  check<typeof res3, Promise<string>, Test.Pass>(),
+  check<typeof res4, Promise<number>, Test.Pass>(),
+  check<typeof res5, Promise<string>, Test.Pass>(),
+  check<typeof res6, Promise<number>, Test.Pass>(),
+  check<typeof res7, Promise<string>, Test.Pass>(),
+  check<typeof res8, Promise<number>, Test.Pass>(),
+  check<typeof res9, number, Test.Pass>(),
+  check<typeof res10, Promise<number>, Test.Pass>(),
+  check<typeof res11, Promise<number>, Test.Pass>(),
+  check<typeof res12, Promise<number>, Test.Pass>(),
+  check<typeof res13, Promise<number>, Test.Pass>(),
+  check<typeof res14, never, Test.Pass>(),
+  check<typeof res15, Promise<never>, Test.Pass>(),
+  check<typeof res16, never, Test.Pass>(),
+  check<typeof res17, Promise<never>, Test.Pass>(),
+  check<typeof res18, Promise<string>, Test.Pass>(),
+]);