nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: marpple/FxTS
Pull request #57 (2021-12-08 07:17:20)

fix: every type
It seems better to follow [mdn every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every)

when array is empry, `every` result is true 


Patch:
diff --git a/src/every.ts b/src/every.ts
index fa9e381e..544151a5 100644
--- a/src/every.ts
+++ b/src/every.ts
@@ -23,7 +23,7 @@ import Arrow from "./types/Arrow";
  * {@link https://codesandbox.io/s/fxts-every-g91dh | Try It}
  */
 
-function every<A extends readonly []>(f: Arrow, iterable: A): false;
+function every<A extends readonly []>(f: Arrow, iterable: A): true;
 
 // prettier-ignore
 function every<A, B = unknown>(
@@ -59,6 +59,7 @@ function every<
       map(f, iterable as Iterable<IterableInfer<A>>),
       takeUntil(not),
       reduce((a, b) => a && b),
+      (a) => a ?? true,
       Boolean,
     );
   }
@@ -68,6 +69,7 @@ function every<
       map(f, iterable as AsyncIterable<IterableInfer<A>>),
       takeUntil(not),
       reduce((a, b) => a && b),
+      (a) => a ?? true,
       Boolean,
     );
   }


Test patch:
diff --git a/test/every.spec.ts b/test/every.spec.ts
index 9b265a31..84bf13de 100644
--- a/test/every.spec.ts
+++ b/test/every.spec.ts
@@ -3,11 +3,8 @@ import { AsyncFunctionException } from "../src/_internal/error";
 
 describe("every", function () {
   describe("sync", function () {
-    it("should return 'false' if given 'Iterable' is an empty array", function () {
-      expect(every((a) => a, [])).toEqual(false);
-    });
-
     it.each([
+      [(a: number) => a % 2 === 0, [], true],
       [(a: number) => a % 2 === 0, [2, 4, 6, 8, 10], true],
       [(a: number) => a % 2 === 0, [1, 4, 6, 8, 10], false],
       [(a: number) => a % 2 === 0, [2, 4, 7, 8, 10], false],
diff --git a/type-check/every.test.ts b/type-check/every.test.ts
index 6b83d02c..d7f33c10 100644
--- a/type-check/every.test.ts
+++ b/type-check/every.test.ts
@@ -16,7 +16,7 @@ const res3 = pipe(
 );
 
 checks([
-  check<typeof res0, false, Test.Pass>(),
+  check<typeof res0, true, Test.Pass>(),
   check<typeof res1, boolean, Test.Pass>(),
   check<typeof res2, boolean, Test.Pass>(),
   check<typeof res3, Promise<boolean>, Test.Pass>(),
Repository: marpple/FxTS
Pull request #101 (2021-12-20 11:38:50)

fix: apply differenceBy uniq
In case of a primitive value, up to uniq is applied.


Patch:
diff --git a/src/Lazy/differenceBy.ts b/src/Lazy/differenceBy.ts
index 0c4480ba..6c6e9784 100644
--- a/src/Lazy/differenceBy.ts
+++ b/src/Lazy/differenceBy.ts
@@ -3,6 +3,8 @@ import reject from "./reject";
 import pipe1 from "../pipe1";
 import toAsync from "./toAsync";
 import toArray from "../toArray";
+import uniq from "./uniq";
+import pipe from "../pipe";
 import concurrent, { isConcurrent } from "./concurrent";
 import { isAsyncIterable, isIterable } from "../_internal/utils";
 
@@ -16,7 +18,12 @@ function* sync<T>(
   iterable2: Iterable<T>,
 ) {
   const set = new Set(map(f, iterable1));
-  yield* reject((a) => hasValue(set, f(a)), iterable2);
+
+  yield* pipe(
+    iterable2,
+    reject((a) => hasValue(set, f(a))),
+    uniq,
+  );
 }
 
 async function* asyncSequential<T>(
@@ -25,7 +32,12 @@ async function* asyncSequential<T>(
   iterable2: AsyncIterable<T>,
 ) {
   const set = new Set(await toArray(map(f, iterable1)));
-  yield* reject((a) => hasValue(set, f(a)), iterable2);
+
+  yield* pipe(
+    iterable2,
+    reject((a) => hasValue(set, f(a))),
+    uniq,
+  );
 }
 
 function async<T>(


Test patch:
diff --git a/test/Lazy/difference.spec.ts b/test/Lazy/difference.spec.ts
index 6ea5ce4c..7a900cda 100644
--- a/test/Lazy/difference.spec.ts
+++ b/test/Lazy/difference.spec.ts
@@ -8,7 +8,7 @@ describe("difference", function () {
     it.each([
       [
         [1, 2, 3, 4],
-        [3, 4, 5, 6],
+        [3, 4, 5, 6, 5, 3],
         [5, 6],
       ],
       ["abcd", "cdefg", ["e", "f", "g"]],
@@ -28,7 +28,7 @@ describe("difference", function () {
 
   describe("async", function () {
     it.each([
-      [toAsync([1, 2, 3, 4]), toAsync([3, 4, 5, 6]), [5, 6]],
+      [toAsync([1, 2, 3, 4]), toAsync([3, 4, 5, 6, 5, 3]), [5, 6]],
       [[1, 2, 3, 4], toAsync([3, 4, 5, 6]), [5, 6]],
       [toAsync([1, 2, 3, 4]), [3, 4, 5, 6], [5, 6]],
       ["abcd", "cdefg", ["e", "f", "g"]],
Repository: marpple/FxTS
Pull request #111 (2021-12-22 06:47:14)

fix: handle sum type error

fix it to occur an error below situation
const res0 = sum([1, 'a']); // error


Patch:
diff --git a/src/sum.ts b/src/sum.ts
index 534bf0c2..4a6c800d 100644
--- a/src/sum.ts
+++ b/src/sum.ts
@@ -1,13 +1,8 @@
 import add from "./add";
 import reduce from "./reduce";
-import IterableInfer from "./types/IterableInfer";
 import ReturnValueType from "./types/ReturnValueType";
 import { isAsyncIterable, isIterable } from "./_internal/utils";
 
-type ReturnSumType<
-  A extends Iterable<number | string> | AsyncIterable<number | string>,
-> = ReturnValueType<A, IterableInfer<A>>;
-
 /**
  * Adds all the elements of a Iterable/AsyncIterable.
  *
@@ -20,14 +15,18 @@ type ReturnSumType<
  * ```
  */
 function sum<
-  A extends Iterable<number | string> | AsyncIterable<number | string>,
->(iterable: A): ReturnSumType<A> {
+  A extends
+    | Iterable<number>
+    | AsyncIterable<number>
+    | Iterable<string>
+    | AsyncIterable<string>,
+>(iterable: A): ReturnValueType<A> {
   if (isIterable(iterable)) {
-    return reduce(add, iterable) as ReturnSumType<A>;
+    return reduce(add, iterable) as ReturnValueType<A>;
   }
 
   if (isAsyncIterable(iterable)) {
-    return reduce(add, iterable) as ReturnSumType<A>;
+    return reduce(add, iterable) as ReturnValueType<A>;
   }
 
   throw new TypeError("'iterable' must be type of Iterable or AsyncIterable");


Test patch:
diff --git a/type-check/sum.test.ts b/type-check/sum.test.ts
index ad4901ef..fe536315 100644
--- a/type-check/sum.test.ts
+++ b/type-check/sum.test.ts
@@ -3,6 +3,7 @@ import { sum, pipe, toAsync } from "../src";
 
 const { checks, check } = Test;
 
+// const res0 = sum([1, 'a']); // error
 const res1 = sum([1, 2]);
 const res2 = sum(["a", "b"]);
 const res3 = sum(toAsync([1, 2]));
Repository: marpple/FxTS
Pull request #124 (2022-01-07 06:38:20)

fix: support async tap when curried

It should support asynchronous function when `tap` is curried




Patch:
diff --git a/src/tap.ts b/src/tap.ts
index 311d85d7..9c063e2e 100644
--- a/src/tap.ts
+++ b/src/tap.ts
@@ -31,9 +31,7 @@ function tap<T, U>(
   | Promise<T>
   | ((v: T) => U extends Promise<any> ? Promise<Awaited<T>> : T) {
   if (v === undefined) {
-    return (v: T) =>
-      (v instanceof Promise ? v.then(f) : f(v as Awaited<T>),
-      v) as U extends Promise<any> ? Promise<Awaited<T>> : T;
+    return (v: T) => tap(f, v);
   }
 
   const res = v instanceof Promise ? v.then(f) : f(v as Awaited<T>);


Test patch:
diff --git a/test/tap.spec.ts b/test/tap.spec.ts
index c1bf837e..20bda077 100644
--- a/test/tap.spec.ts
+++ b/test/tap.spec.ts
@@ -1,4 +1,4 @@
-import { delay, tap } from "../src/index";
+import { delay, map, pipe, range, tap, toArray, toAsync } from "../src/index";
 import { callFuncAfterTime } from "./utils";
 
 describe("tap", function () {
@@ -34,5 +34,12 @@ describe("tap", function () {
       expect(fn).toBeCalled();
       expect(res).toEqual(10);
     }, 1050);
+
+    it("should support asynchronous when curried.", async function () {
+      const fn = jest.fn();
+      callFuncAfterTime(fn, 500);
+      await pipe(range(5), toAsync, map(tap(() => delay(100))), toArray);
+      expect(fn).toBeCalled();
+    });
   });
 });
Repository: marpple/FxTS
Pull request #128 (2022-01-13 03:33:38)

Fix join


Patch:
diff --git a/src/join.ts b/src/join.ts
index 376ee330..4b894d6e 100644
--- a/src/join.ts
+++ b/src/join.ts
@@ -9,11 +9,13 @@ type ReturnJoinType<T extends Iterable<unknown> | AsyncIterable<unknown>> =
     : never;
 
 function sync<A>(sep: string, iterable: Iterable<A>) {
-  return reduce((a: string, b) => `${a}${sep}${b}`, iterable);
+  return reduce((a: string, b) => `${a}${sep}${b}`, iterable) ?? "";
 }
 
 function async<A>(sep: string, iterable: AsyncIterable<A>) {
-  return reduce((a: string, b) => `${a}${sep}${b}`, iterable);
+  return reduce((a: string, b) => `${a}${sep}${b}`, iterable).then(
+    (a) => a ?? "",
+  );
 }
 
 /**


Test patch:
diff --git a/test/join.spec.ts b/test/join.spec.ts
index 11243d12..45d32b50 100644
--- a/test/join.spec.ts
+++ b/test/join.spec.ts
@@ -1,7 +1,14 @@
+import { asyncEmpty, empty } from "../src/_internal/utils";
 import { filter, join, map, pipe, toAsync } from "../src/index";
 
 describe("join", function () {
   describe("sync", function () {
+    it("should return an empty string if there are no iterable items", function () {
+      expect(join(", ", "")).toEqual("");
+      expect(join(", ", [])).toEqual("");
+      expect(join(", ", empty())).toEqual("");
+    });
+
     it("should be joined with separator", function () {
       expect(join(", ", "hello")).toEqual("h, e, l, l, o");
     });
@@ -26,6 +33,10 @@ describe("join", function () {
   });
 
   describe("async", function () {
+    it("should return an empty string if there are no iterable items", async function () {
+      expect(await join(", ", asyncEmpty())).toEqual("");
+    });
+
     it("should be discarded elements by length", async function () {
       const res = await join("-", toAsync([1, 2, 3, 4, 5]));
       expect(res).toEqual("1-2-3-4-5");
Repository: marpple/FxTS
Pull request #150 (2022-04-04 02:25:35)

feat: add `isUndefined` function

add `isUndefined` function


Patch:
diff --git a/src/index.ts b/src/index.ts
index 83ddd560..c33113bd 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -22,6 +22,7 @@ import isNil from "./isNil";
 import isNumber from "./isNumber";
 import isObject from "./isObject";
 import isString from "./isString";
+import isUndefined from "./isUndefined";
 import join from "./join";
 import juxt from "./juxt";
 import last from "./last";
@@ -74,6 +75,7 @@ export {
   isNumber,
   isObject,
   isString,
+  isUndefined,
   join,
   juxt,
   last,
diff --git a/src/isUndefined.ts b/src/isUndefined.ts
new file mode 100644
index 00000000..39dd9056
--- /dev/null
+++ b/src/isUndefined.ts
@@ -0,0 +1,14 @@
+/**
+ * Returns true if `a` is a undefined.
+ *
+ * @example
+ * ```ts
+ * isUndefined(undefined); // true
+ * isUndefined(2); // false
+ * ```
+ */
+function isUndefined(a: any): a is undefined {
+  return typeof a === "undefined";
+}
+
+export default isUndefined;
diff --git a/website/function.json b/website/function.json
index cfaa4550..f417d05f 100644
--- a/website/function.json
+++ b/website/function.json
@@ -68,6 +68,7 @@
     "isNumber",
     "isObject",
     "isString",
+    "isUndefined",
     "join",
     "juxt",
     "last",


Test patch:
diff --git a/test/isUndefined.spec.ts b/test/isUndefined.spec.ts
new file mode 100644
index 00000000..23b68b4e
--- /dev/null
+++ b/test/isUndefined.spec.ts
@@ -0,0 +1,16 @@
+import isUndefined from "../src/isUndefined";
+
+describe("isUndefined", function () {
+  it.each([2, true, null, {}, [], Symbol("a"), "a"])(
+    "given non undefined then should be false",
+    function (a) {
+      const result = isUndefined(a);
+      expect(result).toEqual(false);
+    },
+  );
+
+  it("given undefined then should be true", function () {
+    const result = isUndefined(undefined);
+    expect(result).toEqual(true);
+  });
+});
diff --git a/type-check/isUndefined.test.ts b/type-check/isUndefined.test.ts
new file mode 100644
index 00000000..f6268cbd
--- /dev/null
+++ b/type-check/isUndefined.test.ts
@@ -0,0 +1,14 @@
+import * as Test from "../src/types/Test";
+import { filter, isUndefined, pipe } from "../src";
+
+const { checks, check } = Test;
+
+const res1 = isUndefined(undefined);
+const res2 = isUndefined(3);
+const res3 = pipe([1, undefined, 2], filter(isUndefined));
+
+checks([
+  check<typeof res1, boolean, Test.Pass>(),
+  check<typeof res2, boolean, Test.Pass>(),
+  check<typeof res3, IterableIterator<undefined>, Test.Pass>(),
+]);
Repository: marpple/FxTS
Pull request #237 (2023-10-13 16:16:47)

feat: isEmpty should also work for Map and Set
Correctly report empty on Map and Set


Patch:
diff --git a/src/isEmpty.ts b/src/isEmpty.ts
index b42e6117..43457b25 100644
--- a/src/isEmpty.ts
+++ b/src/isEmpty.ts
@@ -11,6 +11,8 @@ import isNil from "./isNil";
  * isEmpty(null) // true
  * isEmpty(undefined) // true
  * isEmpty("") // true
+ * isEmpty(new Map()) // true
+ * isEmpty(new Set()) // true
  *
  * isEmpty(0) // false
  * isEmpty(false) // false
@@ -33,6 +35,8 @@ const isEmpty = <T>(value: T): boolean => {
 
   if (value === "") return true;
 
+  if (value instanceof Map || value instanceof Set) return value.size === 0; // if value is a Map or Set and have no item.
+
   return false;
 };
 


Test patch:
diff --git a/test/isEmpty.spec.ts b/test/isEmpty.spec.ts
index 4cb2ad09..6cdecfc1 100644
--- a/test/isEmpty.spec.ts
+++ b/test/isEmpty.spec.ts
@@ -15,6 +15,10 @@ describe("isEmpty", function () {
     [[1], false],
     ["", true],
     ["a", false],
+    [new Map(), true],
+    [new Map([["key", "value"]]), false],
+    [new Set(), true],
+    [new Set(["value"]), false],
     [Symbol(""), false],
     // eslint-disable-next-line @typescript-eslint/no-empty-function
     [function () {}, false],
Repository: marpple/FxTS
Pull request #247 (2024-02-18 11:48:51)

refactor: reduceLazy move to strict folder
@Phryxia

https://github.com/marpple/FxTS/pull/245


There is something I missed in the PR, so correct it

Functions in the Lazy folder must return iterable/asyncIterable.
`reduceLazy` must be in the strict folder.


Patch:
diff --git a/src/Lazy/index.ts b/src/Lazy/index.ts
index 5c31baed..222cb7f0 100644
--- a/src/Lazy/index.ts
+++ b/src/Lazy/index.ts
@@ -24,7 +24,6 @@ import pipeLazy from "./pipeLazy";
 import pluck from "./pluck";
 import prepend from "./prepend";
 import range from "./range";
-import reduceLazy from "./reduceLazy";
 import reject from "./reject";
 import repeat from "./repeat";
 import reverse from "./reverse";
@@ -71,7 +70,6 @@ export {
   prepend,
   range,
   reject,
-  reduceLazy,
   repeat,
   reverse,
   scan,
diff --git a/src/index.ts b/src/index.ts
index 3c56a873..1b22f994 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -51,6 +51,7 @@ import pipe1 from "./pipe1";
 import prop from "./prop";
 import props from "./props";
 import reduce from "./reduce";
+import reduceLazy from "./reduceLazy";
 import size from "./size";
 import some from "./some";
 import sort from "./sort";
@@ -120,6 +121,7 @@ export {
   prop,
   props,
   reduce,
+  reduceLazy,
   size,
   unless,
   some,
diff --git a/src/Lazy/reduceLazy.ts b/src/reduceLazy.ts
similarity index 92%
rename from src/Lazy/reduceLazy.ts
rename to src/reduceLazy.ts
index a0784e76..c8951966 100644
--- a/src/Lazy/reduceLazy.ts
+++ b/src/reduceLazy.ts
@@ -1,7 +1,7 @@
-import reduce from "../reduce";
-import type IterableInfer from "../types/IterableInfer";
-import type { AsyncReducer, SyncReducer } from "../types/Reducer";
-import type ReturnValueType from "../types/ReturnValueType";
+import reduce from "./reduce";
+import type IterableInfer from "./types/IterableInfer";
+import type { AsyncReducer, SyncReducer } from "./types/Reducer";
+import type ReturnValueType from "./types/ReturnValueType";
 
 type InferCarrier<T> = T extends AsyncIterable<infer R>
   ? AsyncIterable<R>
diff --git a/website/function.json b/website/function.json
index c6c320ed..d6d33600 100644
--- a/website/function.json
+++ b/website/function.json
@@ -26,7 +26,6 @@
     "pluck",
     "prepend",
     "range",
-    "reduceLazy",
     "reject",
     "repeat",
     "reverse",
@@ -97,6 +96,7 @@
     "prop",
     "props",
     "reduce",
+    "reduceLazy",
     "size",
     "some",
     "sort",


Test patch:
diff --git a/type-check/Lazy/reduceLazy.test.ts b/type-check/reduceLazy.test.ts
similarity index 94%
rename from type-check/Lazy/reduceLazy.test.ts
rename to type-check/reduceLazy.test.ts
index 587d6cec..a99e7d36 100644
--- a/type-check/Lazy/reduceLazy.test.ts
+++ b/type-check/reduceLazy.test.ts
@@ -1,6 +1,6 @@
-import { pipe, toAsync } from "../../src";
-import reduceLazy from "../../src/Lazy/reduceLazy";
-import * as Test from "../../src/types/Test";
+import { pipe, toAsync } from "../src";
+import reduceLazy from "../src/reduceLazy";
+import * as Test from "../src/types/Test";
 
 const { checks, check } = Test;
Repository: marpple/FxTS
Pull request #318 (2025-04-13 13:03:46)

fix: change `fx.zip` evaluation arguments  order
Fixes the order in which zip evaluates arguments is reversed.


Patch:
diff --git a/src/Lazy/fx.ts b/src/Lazy/fx.ts
index 96dfc550..f05a17e1 100644
--- a/src/Lazy/fx.ts
+++ b/src/Lazy/fx.ts
@@ -228,8 +228,13 @@ class FxAsyncIterable<A> {
    *
    * see {@link https://fxts.dev/docs/zip | zip}
    */
-  zip<B>(iterable: Iterable<B> | AsyncIterable<B>): FxAsyncIterable<[A, B]> {
-    return new FxAsyncIterable(zip(this.asyncIterable, iterable));
+  zip<B>(iterable: Iterable<B> | AsyncIterable<B>): FxAsyncIterable<[B, A]> {
+    return new FxAsyncIterable(
+      zip(
+        isAsyncIterable(iterable) ? iterable : toAsync(iterable),
+        this.asyncIterable,
+      ),
+    );
   }
 
   /**
@@ -562,8 +567,8 @@ export class FxIterable<A> {
    *
    * see {@link https://fxts.dev/docs/zip | zip}
    */
-  zip<B>(iterable: Iterable<B>): FxIterable<[A, B]> {
-    return new FxIterable(zip(this.iterable, iterable));
+  zip<B>(iterable: Iterable<B>): FxIterable<[B, A]> {
+    return new FxIterable(zip(iterable, this.iterable));
   }
 
   /**


Test patch:
diff --git a/test/Lazy/zip.spec.ts b/test/Lazy/zip.spec.ts
index 5d653142..4c18e1a1 100644
--- a/test/Lazy/zip.spec.ts
+++ b/test/Lazy/zip.spec.ts
@@ -100,17 +100,17 @@ describe("zip", function () {
       const res1 = fx([1, 2, 3]).zip(["5", "6", "7", "8"]).toArray();
 
       expect(res1).toEqual([
-        [1, "5"],
-        [2, "6"],
-        [3, "7"],
+        ["5", 1],
+        ["6", 2],
+        ["7", 3],
       ]);
 
       const res2 = fx([1, 2, 3, 4]).zip(["5", "6", "7"]).toArray();
 
       expect(res2).toEqual([
-        [1, "5"],
-        [2, "6"],
-        [3, "7"],
+        ["5", 1],
+        ["6", 2],
+        ["7", 3],
       ]);
     });
   });
@@ -202,9 +202,9 @@ describe("zip", function () {
         .toArray();
 
       expect(res1).toEqual([
-        [1, "5"],
-        [2, "6"],
-        [3, "7"],
+        ["5", 1],
+        ["6", 2],
+        ["7", 3],
       ]);
 
       const res2 = await fx([1, 2, 3, 4])
@@ -213,9 +213,9 @@ describe("zip", function () {
         .toArray();
 
       expect(res2).toEqual([
-        [1, "5"],
-        [2, "6"],
-        [3, "7"],
+        ["5", 1],
+        ["6", 2],
+        ["7", 3],
       ]);
     });
 
diff --git a/type-check/Lazy/zip.test.ts b/type-check/Lazy/zip.test.ts
index ad7d7663..e7d565c7 100644
--- a/type-check/Lazy/zip.test.ts
+++ b/type-check/Lazy/zip.test.ts
@@ -24,6 +24,6 @@ checks([
   check<typeof res4, IterableIterator<[string, number]>, Test.Pass>(),
   check<typeof res5, AsyncIterableIterator<[string, number]>, Test.Pass>(),
   check<typeof res6, AsyncIterableIterator<[string, number]>, Test.Pass>(),
-  check<typeof res7, [number, string][], Test.Pass>(),
-  check<typeof res8, Promise<[number, string][]>, Test.Pass>(),
+  check<typeof res7, [string, number][], Test.Pass>(),
+  check<typeof res8, Promise<[string, number][]>, Test.Pass>(),
 ]);
Repository: marpple/FxTS
Pull request #320 (2025-05-05 10:04:12)

fix: add filter overload to fx
Fixes #

I encountered some inconvenience when using the filter method on the fx object.
It seems that when using a type guard function with filter, it doesn't affect the resulting type as expected.
To address this, I added an overload to the filter method on the fx object.
I’d appreciate it if you could take a look. 🙇‍♂️

before: 
<img width="383" alt="image" src="https://github.com/user-attachments/assets/8048e458-86c9-4987-bbfa-a7018db62a39" />

after:
<img width="383" alt="image" src="https://github.com/user-attachments/assets/0139915b-ecf2-40d7-a618-e5b6a4181b47" />



Patch:
diff --git a/src/Lazy/fx.ts b/src/Lazy/fx.ts
index f05a17e1..5ba55994 100644
--- a/src/Lazy/fx.ts
+++ b/src/Lazy/fx.ts
@@ -111,6 +111,8 @@ class FxAsyncIterable<A> {
    *
    * see {@link https://fxts.dev/docs/filter | filter}
    */
+  filter<B extends A>(f: (a: A) => a is B): FxAsyncIterable<B>;
+  filter(f: (a: A) => unknown): FxAsyncIterable<A>;
   filter(f: (a: A) => unknown): FxAsyncIterable<A> {
     return new FxAsyncIterable(filter(f, this.asyncIterable));
   }
@@ -452,6 +454,8 @@ export class FxIterable<A> {
    *
    * see {@link https://fxts.dev/docs/filter | filter}
    */
+  filter<B extends A>(f: (a: A) => a is B): FxIterable<B>;
+  filter(f: (a: A) => unknown): FxIterable<A>;
   filter(f: (a: A) => unknown): FxIterable<A> {
     return new FxIterable(filter(f, this.iterable));
   }


Test patch:
diff --git a/type-check/Lazy/fx.test.ts b/type-check/Lazy/fx.test.ts
index b572c1dc..dea2510c 100644
--- a/type-check/Lazy/fx.test.ts
+++ b/type-check/Lazy/fx.test.ts
@@ -24,6 +24,10 @@ const res7 = fx(toAsync([1, 2, 3]))
 const res8 = [...fx([1, 2, 3])];
 const res9 = [...fx("abc")];
 
+const res10 = fx([1, null, 2, null, 3])
+  .filter((n): n is number => n !== null)
+  .toArray();
+
 checks([
   check<typeof res1, Cast<Iterable<number>, typeof res1>, Test.Pass>(),
   check<typeof res2, number[], Test.Pass>(),
@@ -34,4 +38,5 @@ checks([
   check<typeof res7, Promise<number[]>, Test.Pass>(),
   check<typeof res8, number[], Test.Pass>(),
   check<typeof res9, string[], Test.Pass>(),
+  check<typeof res10, number[], Test.Pass>(),
 ]);
Repository: marpple/FxTS
Pull request #323 (2025-06-13 06:42:47)

fix: entries return type
A situation where the type does not work based on the JavaScript runtime behavior.

Modified to transfer types based on the JavaScript runtime behavior.

Both string and number are entered as key values ​​in the object.
```
var obj = { 2025 : 'hello' }
obj[2025] // hello
obj['2025'] // hello
```

The results of `Object.keys(obj)`, `Object.entries`, and `for k in obj` are all strings, so if the first key of `entries` is a number, the type is transferred as string.

The existing response type is maintained(Maintaining backward compatibility)


Patch:
diff --git a/src/Lazy/entries.ts b/src/Lazy/entries.ts
index 302ddd7d..bbc83952 100644
--- a/src/Lazy/entries.ts
+++ b/src/Lazy/entries.ts
@@ -1,7 +1,14 @@
-type Entries<
-  T extends Record<string, any>,
-  K extends keyof T,
-> = K extends string ? [K, T[K]] : never;
+import type Key from "../types/Key";
+
+type NumberToString<T extends number> = `${T}` extends infer R extends string
+  ? R
+  : never;
+
+type Entries<T extends Record<Key, any>, K extends keyof T> = K extends number
+  ? [NumberToString<K>, T[K]]
+  : K extends Key
+  ? [K, T[K]]
+  : never;
 
 /**
  *
@@ -18,7 +25,7 @@ type Entries<
  * see {@link https://fxts.dev/docs/fromEntries | fromEntries}
  */
 
-function* entries<T extends Record<string, any>>(
+function* entries<T extends Record<Key, any>>(
   obj: T,
 ): Generator<Entries<T, keyof T>, void> {
   for (const k in obj) {


Test patch:
diff --git a/type-check/Lazy/entries.test.ts b/type-check/Lazy/entries.test.ts
index ae57dd87..bba7350b 100644
--- a/type-check/Lazy/entries.test.ts
+++ b/type-check/Lazy/entries.test.ts
@@ -22,6 +22,11 @@ type Obj = {
 const fn = (obj: Obj) => entries(obj);
 const res3 = fn({ hello: 3 });
 
+const obj2: {
+  [x: number]: string;
+} = { 2025: "year", 2024: "year" };
+const res4 = entries(obj2);
+
 checks([
   check<
     typeof res1,
@@ -51,4 +56,9 @@ checks([
   >(),
 
   check<typeof res3, Generator<[string, number], void, unknown>, Test.Pass>(),
+  check<
+    typeof res4,
+    Generator<[`${number}`, string], void, unknown>,
+    Test.Pass
+  >(),
 ]);