Repository: marpple/FxTS (ts)

Issue:
The curried function returned from the fxts/curry is incorrectly inferred.
# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 💻 Code

<!-- Please post the relevant code sample here as well-->
<!-- How to reproduce it -->

```ts
import { each, map, pipe, curry } from '@fxts/core';

const add = curry((a: number, b: number) => a + b);

pipe([1, 2, 3], map(add(10)), map(add(100)), each(console.log));
```

### 🙁 Actual behavior

Typescript can't correctly infer the type of add when it executed in map or pipe.

* add(10) in first map
![image](https://user-images.githubusercontent.com/29361570/152823929-2a04fe29-a79c-47f2-bdd8-c3f729cc9864.png)

* add(100) in second map
![image](https://user-images.githubusercontent.com/29361570/152824342-c2dfe4cb-3f80-4b30-8836-dda1df0f142b.png)

More precisely, every functions whose type is compatible with `<X>(f: (...args) => X): X` can't infer if callback is executed curried function.

`Curry<F extends (...args: any[]) => any>` type return the below type.
```ts
<
  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;
```

I think typescript infers type `f: (...args) => X`, not type `X` as the return type of curried function, because `ReturnType` uses the `infer` keyword and Curry passes `R = ReturnType` recursively.

So we need to ensure that the type of `ReturnType<F>` can be fixed only once when the `curry` function is initially executed.
```ts
<
  T extends any[],
  G = Drop<Length<T>, Parameters<F>>,
>(
  ...args: Cast<T, Gaps<Parameters<F>>>
) => G extends [any, ...any[]]
  ? Curry<(...args: G) => ReturnType<F>>
  : ReturnType<F>;
```


### 🙂 Expected behavior

<!-- What you expected to happen instead, and why -->
* add(10) in first map
![image](https://user-images.githubusercontent.com/29361570/152830379-f7ec06f9-a4f8-47bc-9edb-e4a7acf5a40f.png)


* add(100) in second map
![image](https://user-images.githubusercontent.com/29361570/152830422-08e4fa04-2783-43d6-99fd-b9194d913b2b.png)

---

### Version Information

<!-- Please let me know your environment -->

- Operating system: macOS Big Sur 11.1
- Typescript: ^4.5.4
- Nodejs: v17.3.1


Pull request:
fix: fix return type in Curry type
I wrote the details on the #139 

Fixes #139 


Patch:
diff --git a/src/types/Curry.ts b/src/types/Curry.ts
index 8c55fc47..4c7bb799 100644
--- a/src/types/Curry.ts
+++ b/src/types/Curry.ts
@@ -11,9 +11,10 @@ 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;
+) => G extends [any, ...any[]]
+  ? Curry<(...args: G) => ReturnType<F>>
+  : ReturnType<F>;
 
 export default Curry;


Test patch:
diff --git a/test/curry.spec.ts b/test/curry.spec.ts
index 3e4578d3..95f24168 100644
--- a/test/curry.spec.ts
+++ b/test/curry.spec.ts
@@ -1,4 +1,4 @@
-import { curry } from "../src";
+import { curry, filter, map, pipe, toArray } from "../src";
 
 describe("curry", function () {
   it("should not change a unary function", function () {
@@ -17,4 +17,21 @@ describe("curry", function () {
     expect(curried()(1, 2, 3)).toBe(6);
     expect(curried(1)()(2, 3)).toBe(6);
   });
+
+  it("curried function should be able to be used within the pipeline.", function () {
+    const add = curry((a: number, b: number, c: number) => a + b + c);
+    const multiply = curry((a: number, b: number) => a * b);
+    const lt = curry((l: number, r: number) => l < r);
+
+    expect(pipe(1, add(2, 3), multiply(10))).toBe(60);
+    expect(
+      pipe(
+        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+        map(add(2, 3)),
+        map(multiply(10)),
+        filter(lt(100)),
+        toArray,
+      ),
+    ).toEqual([110, 120, 130, 140, 150]);
+  });
 });
diff --git a/type-check/curry.test.ts b/type-check/curry.test.ts
index 3fac72c9..fc7ea486 100644
--- a/type-check/curry.test.ts
+++ b/type-check/curry.test.ts
@@ -1,7 +1,7 @@
 import * as Test from "../src/types/Test";
 import Curry from "../src/types/Curry";
 import { curry, pipe, toAsync } from "../src";
-import { filter } from "../src/Lazy";
+import { filter, map } from "../src/Lazy";
 
 const { checks, check } = Test;
 
@@ -15,9 +15,13 @@ const res3 = res2(true);
 const res4 = res2(false, 1, 2, 3);
 
 const strictEq = curry(<T>(left: T, right: T) => left === right);
+const add = curry((a: number, b: number) => a + b);
 
 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)));
+const res7 = pipe(1, add(2), add(3));
+const res8 = pipe([1, 2, 3], map(add(10)), map(add(100)));
+const res9 = pipe([1, 2, 3], toAsync, map(add(10)), map(add(100)));
 
 checks([
   check<
@@ -34,4 +38,7 @@ checks([
   check<typeof res4, string, Test.Pass>(),
   check<typeof res5, IterableIterator<number>, Test.Pass>(),
   check<typeof res6, AsyncIterableIterator<number>, Test.Pass>(),
+  check<typeof res7, number, Test.Pass>(),
+  check<typeof res8, IterableIterator<number>, Test.Pass>(),
+  check<typeof res9, AsyncIterableIterator<number>, Test.Pass>(),
 ]);