Repository: marpple/FxTS (ts)

Issue:
User-Defined Type Guards not working properly in `reject` function
# Suggestion
reproduction: https://codesandbox.io/s/magical-snow-wrrz4m?file=/src/index.ts

## 💻 Use Cases
```ts
import { filter, reject, toArray } from "@fxts/core";

type ObjA = { _type: "A"; a: string; b: string };
type ObjB = { _type: "B"; a: number; b: number };

const list = [
  { _type: "A", a: "1", b: "2" },
  { _type: "B", a: 3, b: 4 },
  { _type: "A", a: "1", b: "2" },
  { _type: "B", a: 3, b: 4 }
];

const res = toArray(reject((a): a is ObjB => a._type === "B", list));

console.log(res); // `res` must be inferred to be of type `ObjA[]`
```

Pull request description:
Feat/180
Fixes #180

Improved type inference of `reject` function when receiving custom typeguard function as an argument.
```ts
const res = pipe(
  [1, 2, 3, "4", "5", "6", null, undefined],
  reject(isNil), // (a): a is null | undefined => a == null
  reject(isString), // (a): a is string => typeof a === "string"
  toArray,
);
// As-is
// typeof res == (number, string | null | undefined)[]

// To-be
// typeof res == number[]
```

Patch:
diff --git a/.commitlintrc b/.commitlintrc
index c86a9a30..2b7b4371 100644
--- a/.commitlintrc
+++ b/.commitlintrc
@@ -1,3 +1,6 @@
 {
-  extends: ["@commitlint/config-conventional"]
+  extends: ["@commitlint/config-conventional"],
+  rules: {
+    "header-max-length": [1, 'always', 110]
+  }
 }
diff --git a/src/Lazy/reject.ts b/src/Lazy/reject.ts
index f7a7da0a..89f291c5 100644
--- a/src/Lazy/reject.ts
+++ b/src/Lazy/reject.ts
@@ -53,6 +53,28 @@ import ReturnIterableIteratorType from "../types/ReturnIterableIteratorType";
  * see {@link https://fxts.dev/docs/pipe | pipe}, {@link https://fxts.dev/docs/toAsync | toAsync},
  * {@link https://fxts.dev/docs/toArray | toArray}
  */
+
+function reject<A, B extends A>(
+  f: (a: A) => a is B,
+  iterable: Iterable<A>,
+): IterableIterator<Exclude<A, B>>;
+
+function reject<A, B extends A>(
+  f: (a: A) => a is B,
+  iterable: AsyncIterable<A>,
+): AsyncIterableIterator<Exclude<A, B>>;
+
+function reject<
+  A extends Iterable<unknown> | AsyncIterable<unknown>,
+  B extends IterableInfer<A>,
+>(
+  f: (a: IterableInfer<A>) => a is B,
+): (
+  iterable: A,
+) => A extends AsyncIterable<any>
+  ? AsyncIterableIterator<Exclude<IterableInfer<A>, B>>
+  : IterableIterator<Exclude<IterableInfer<A>, B>>;
+
 function reject<A, B = unknown>(
   f: (a: A) => B,
   iterable: Iterable<A>,


Test patch:
diff --git a/type-check/Lazy/reject.test.ts b/type-check/Lazy/reject.test.ts
index 56a1546a..b5b92548 100644
--- a/type-check/Lazy/reject.test.ts
+++ b/type-check/Lazy/reject.test.ts
@@ -1,5 +1,5 @@
 import * as Test from "../../src/types/Test";
-import { toAsync, reject, pipe } from "../../src";
+import { isNil, isString, pipe, reject, toAsync } from "../../src";
 
 const { checks, check } = Test;
 
@@ -25,6 +25,20 @@ const res8 = pipe(
   reject(async (a) => a % 2 === 0),
 );
 
+const res9 = reject(isNil, [1, 2, 3, "4", "5", "6", null, undefined]);
+const res10 = reject(isNil, toAsync([1, 2, 3, "4", "5", "6", null, undefined]));
+const res11 = pipe(
+  [1, 2, 3, "4", "5", "6", null, undefined],
+  reject(isNil),
+  reject(isString),
+);
+const res12 = pipe(
+  [1, 2, 3, "4", "5", "6", null, undefined],
+  toAsync,
+  reject(isNil),
+  reject(isString),
+);
+
 checks([
   check<typeof res1, IterableIterator<number>, Test.Pass>(),
   check<typeof res2, IterableIterator<number>, Test.Pass>(),
@@ -35,4 +49,9 @@ checks([
   check<typeof res6, IterableIterator<number>, Test.Pass>(),
   check<typeof res7, AsyncIterableIterator<number>, Test.Pass>(),
   check<typeof res8, AsyncIterableIterator<number>, Test.Pass>(),
+
+  check<typeof res9, IterableIterator<number | string>, Test.Pass>(),
+  check<typeof res10, AsyncIterableIterator<number | string>, Test.Pass>(),
+  check<typeof res11, IterableIterator<number>, Test.Pass>(),
+  check<typeof res12, AsyncIterableIterator<number>, Test.Pass>(),
 ]);