From 9fe7d8c86e32f773586c1a4e6a8fbedaad3a0474 Mon Sep 17 00:00:00 2001 From: harsha-cpp Date: Sun, 7 Jun 2026 02:03:12 +0530 Subject: [PATCH] use NoInfer on predicate parameter in recurWhile, recurUntil, collectWhile, collectUntil --- ...ix-recurwhile-recuruntil-type-inference.md | 5 +++++ packages/effect/dtslint/Schedule.tst.ts | 21 ++++++++++++++++++- packages/effect/src/Schedule.ts | 8 +++---- packages/effect/test/Schedule.test.ts | 2 +- 4 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 .changeset/fix-recurwhile-recuruntil-type-inference.md diff --git a/.changeset/fix-recurwhile-recuruntil-type-inference.md b/.changeset/fix-recurwhile-recuruntil-type-inference.md new file mode 100644 index 00000000000..724ca27cf3d --- /dev/null +++ b/.changeset/fix-recurwhile-recuruntil-type-inference.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Fix `Schedule.recurWhile` and `Schedule.recurUntil` not inferring the predicate argument type when used with `Effect.repeat`. diff --git a/packages/effect/dtslint/Schedule.tst.ts b/packages/effect/dtslint/Schedule.tst.ts index a51e748bb8f..c39a168fe60 100644 --- a/packages/effect/dtslint/Schedule.tst.ts +++ b/packages/effect/dtslint/Schedule.tst.ts @@ -1,4 +1,4 @@ -import { Console, Schedule } from "effect" +import { Console, Effect, Schedule } from "effect" import { describe, expect, it, when } from "tstyche" describe("Schedule", () => { @@ -31,4 +31,23 @@ describe("Schedule", () => { ) ) }) + + it("recurWhile / recurUntil predicate argument inference", () => { + // predicate arg should infer from the In type of the surrounding Effect.repeat, not default to unknown + const stringEffect = Effect.sync(() => "foo") + + expect(stringEffect.pipe( + Effect.repeat(Schedule.recurWhile((data) => { + expect(data).type.toBe() + return data === "foo" + })) + )).type.toBe>() + + expect(stringEffect.pipe( + Effect.repeat(Schedule.recurUntil((data) => { + expect(data).type.toBe() + return data === "foo" + })) + )).type.toBe>() + }) }) diff --git a/packages/effect/src/Schedule.ts b/packages/effect/src/Schedule.ts index a7414af77a0..581f42e2b00 100644 --- a/packages/effect/src/Schedule.ts +++ b/packages/effect/src/Schedule.ts @@ -456,7 +456,7 @@ export const collectAllOutputs: (self: Schedule) => Sche * @since 2.0.0 * @category Collecting */ -export const collectUntil: (f: Predicate) => Schedule, A> = internal.collectUntil +export const collectUntil: (f: Predicate>) => Schedule, A> = internal.collectUntil /** * Collects all inputs into a `Chunk` until an effectful condition fails. @@ -487,7 +487,7 @@ export const collectUntilEffect: ( * @since 2.0.0 * @category Collecting */ -export const collectWhile: (f: Predicate) => Schedule, A> = internal.collectWhile +export const collectWhile: (f: Predicate>) => Schedule, A> = internal.collectWhile /** * Collects all inputs into a `Chunk` while an effectful condition holds. @@ -1495,7 +1495,7 @@ export const provideService: { * @since 2.0.0 * @category Recurrence Conditions */ -export const recurUntil: (f: Predicate) => Schedule = internal.recurUntil +export const recurUntil: (f: Predicate>) => Schedule = internal.recurUntil /** * A schedule that recurs until the given effectful predicate evaluates to true. @@ -1568,7 +1568,7 @@ export const recurUpTo: (duration: Duration.DurationInput) => Schedule(f: Predicate) => Schedule = internal.recurWhile +export const recurWhile: (f: Predicate>) => Schedule = internal.recurWhile /** * A schedule that recurs as long as the given effectful predicate evaluates to diff --git a/packages/effect/test/Schedule.test.ts b/packages/effect/test/Schedule.test.ts index 3a0866df0d0..2eb5ea9d1ac 100644 --- a/packages/effect/test/Schedule.test.ts +++ b/packages/effect/test/Schedule.test.ts @@ -106,7 +106,7 @@ describe("Schedule", () => { })) it.effect("union of two schedules should continue as long as either wants to continue", () => Effect.gen(function*() { - const schedule = Schedule.recurWhile((b: boolean) => b).pipe(Schedule.union(Schedule.fixed("1 seconds"))) + const schedule = Schedule.recurWhile((b) => b).pipe(Schedule.union(Schedule.fixed("1 seconds"))) const input = Chunk.make(true, false, false, false, false) const result = yield* runCollect(schedule.pipe(Schedule.compose(Schedule.elapsed)), input) const expected = [0, 0, 1, 2, 3].map(Duration.seconds)