Repository: marpple/FxTS (ts)

Issue:
"Type instantiation is excessively deep and possibly infinite" error with large Enum values.
# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

Using a large number of enum results in an error. 

### 💻 Code

<!-- Please post the relevant code sample here as well-->
<!-- How to reproduce it -->

https://codesandbox.io/s/eager-frost-69nrn9?file=/src/App.tsx:0-751

```ts
import { pipe, find } from "@fxts/core";

export default function App() {
  return null;
}

enum Code {
  _1,
  _2,
  _3,
  _4,
  _5,
  _6,
  _7,
  _8,
  _9,
  _10,
  _11,
  _12,
  _13,
  _14,
  _15,
  _16,
  _17,
  _18,
  _19,
  _20,
  _21,
  _22,
  _23,
  _24,
  _25,
  _26,
  _27,
  _28,
  _29,
  _30,
  _31,
  _32,
  _33,
  _34,
  _35,
  _36,
  _37,
  _38,
  _39,
  _40,
  _41,
  _42,
  _43,
  _44,
  _45,
  _46,
  _47,
  _48,
  _49,
  _50,
  _51,
  _52,
  _53,
  _54,
  _55,
  _56,
  _57,
  _58,
  _59,
  _60
}

type data = {
  code: Code;
};

function errorCode(arr: Array<data>, getData: (arr: data) => Code) {
  return pipe(
    arr,
    find((obj) => pipe(obj, getData)), // Type instantiation is excessively deep and possibly infinite.
    (data) => (data !== undefined ? getData(data) : undefined)
  );
}

```

### 🙁 Actual behavior

"Type instantiation is excessively deep and possibly infinite" Error occur.

### 🙂 Expected behavior

No Type Error.

---

### Version Information

<!-- Please let me know your environment -->

- @fxts/core: 0.21.0
- Typescript: 5.2.2 


Pull request:
fix: type instantiation is excessively deep and possibly infinite in pipe
Fixes #234



Patch:
diff --git a/src/Lazy/pipeLazy.ts b/src/Lazy/pipeLazy.ts
index f551eee9..7a430c22 100644
--- a/src/Lazy/pipeLazy.ts
+++ b/src/Lazy/pipeLazy.ts
@@ -41,8 +41,6 @@ import type ReturnPipeType from "../types/ReturnPipeType";
  * see {@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
diff --git a/src/types/ReturnPipeType.ts b/src/types/ReturnPipeType.ts
index 8abd7399..0613bc10 100644
--- a/src/types/ReturnPipeType.ts
+++ b/src/types/ReturnPipeType.ts
@@ -1,5 +1,5 @@
 import type Awaited from "./Awaited";
-import type { TuplifyUnion } from "./ExcludeObject";
+import type Equals from "./Equals";
 import type Head from "./Head";
 import type Tail from "./Tail";
 
@@ -13,7 +13,7 @@ type HasPromise<T extends any[]> = Head<T> extends never
 
 type PossiblyHasPromise<T extends any[]> = Head<T> extends never
   ? false
-  : HasPromise<TuplifyUnion<Head<T>>> extends true
+  : Equals<Head<T>, Head<T> | Promise<Awaited<Head<T>>>> extends 1
   ? true
   : T["length"] extends 0
   ? false
@@ -27,7 +27,7 @@ type PipeLast<T extends any[]> = T["length"] extends 0
   ? never
   : PipeLast<Tail<T>>;
 
-type ReturnPipeType<
+type _ReturnPipeType<
   T extends any[],
   R = Awaited<PipeLast<T>>,
 > = HasPromise<T> extends true
@@ -36,4 +36,11 @@ type ReturnPipeType<
   ? Promise<R> | R
   : R;
 
+type ReturnPipeType<
+  T extends any[],
+  R = Awaited<PipeLast<T>>,
+> = _ReturnPipeType<T, R> extends Promise<never>
+  ? never
+  : _ReturnPipeType<T, R>;
+
 export default ReturnPipeType;


Test patch:
diff --git a/type-check/pipe.test.ts b/type-check/pipe.test.ts
index 3ff210de..59a5934e 100644
--- a/type-check/pipe.test.ts
+++ b/type-check/pipe.test.ts
@@ -73,6 +73,77 @@ const res17 = pipe(
   () => 2,
 );
 
+const Code = {
+  None: "NONE",
+  _00: "00",
+  _11: "11",
+  _13: "13",
+  _15: "15",
+  _17: "17",
+  _19: "19",
+  _21: "21",
+  _23: "23",
+  _25: "25",
+  _27: "27",
+  _29: "29",
+  _32: "32",
+  _34: "34",
+  _41: "41",
+  _43: "43",
+  _46: "46",
+  _52: "52",
+  _54: "54",
+  _56: "56",
+  _58: "58",
+  _62: "62",
+  _64: "64",
+  _66: "66",
+  _68: "68",
+  _72: "72",
+  _81: "81",
+  _83: "83",
+  _85: "85",
+  _96: "96",
+  _10: "10",
+  _12: "12",
+  _14: "14",
+  _16: "16",
+  _18: "18",
+  _20: "20",
+  _22: "22",
+  _24: "24",
+  _26: "26",
+  _28: "28",
+  _31: "31",
+  _33: "33",
+  _36: "36",
+  _42: "42",
+  _44: "44",
+  _51: "51",
+  _53: "53",
+  _55: "55",
+  _57: "57",
+  _61: "61",
+  _63: "63",
+  _65: "65",
+  _67: "67",
+  _71: "71",
+  _73: "73",
+  _74: "74",
+  _75: "75",
+  _76: "76",
+  _82: "82",
+  _84: "84",
+  _95: "95",
+} as const;
+
+type Code = (typeof Code)[keyof typeof Code];
+const res18 = pipe({ code: Code.None }, (_: { code: Code }): Code => Code.None);
+const res19 = pipe(
+  { code: Code.None },
+  async (_: { code: Code }): Promise<Code> => Code.None,
+);
+
 checks([
   check<typeof res1, string, Test.Pass>(),
   check<typeof res2, number, Test.Pass>(),
@@ -91,4 +162,6 @@ checks([
   check<typeof res15, Promise<never>, Test.Pass>(),
   check<typeof res16, never, Test.Pass>(),
   check<typeof res17, Promise<never>, Test.Pass>(),
+  check<typeof res18, Code, Test.Pass>(),
+  check<typeof res19, Promise<Code>, Test.Pass>(),
 ]);