From fc2ff685f4cc9b3e7afc3325026d05444a752b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 16 Jul 2026 23:25:34 +0200 Subject: [PATCH] Add zipLatestAll --- packages/effect-lens-next/src/View.ts | 32 ++++++++++++++++++------ packages/effect-lens/src/Subscribable.ts | 16 ++++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/effect-lens-next/src/View.ts b/packages/effect-lens-next/src/View.ts index 27cd1d8..bc0160d 100644 --- a/packages/effect-lens-next/src/View.ts +++ b/packages/effect-lens-next/src/View.ts @@ -99,6 +99,30 @@ export const mapOptionEffect: { onNone: () => Effect.succeed(Option.none()), }))) +/** Converts typed failures from both channels into `Result` values. */ +export const result = ( + self: View, +): View, never, R> => make({ + get get() { return Effect.result(self.get) }, + get changes() { return Stream.result(self.changes) }, +}) + +/** + * Combines the current values and streams of changes from multiple `View` values. + */ +export const zipLatestAll = []>( + ...elements: T +): View< + [T[number]] extends [never] + ? never + : { [K in keyof T]: T[K] extends View ? A : never }, + [T[number]] extends [never] ? never : T[number] extends View ? E : never, + [T[number]] extends [never] ? never : T[number] extends View ? R : never +> => make({ + get: Effect.all(elements.map(view => view.get)), + changes: Stream.zipLatestAll(...elements.map(view => view.changes)), +}) as any + /** Maps errors from both the current value and the stream of changes. */ export const mapError: { @@ -192,14 +216,6 @@ export const retry: { get changes() { return Stream.retry(self.changes, policy) }, })) -/** Converts typed failures from both channels into `Result` values. */ -export const result = ( - self: View, -): View, never, R> => make({ - get get() { return Effect.result(self.get) }, - get changes() { return Stream.result(self.changes) }, -}) - /** Narrows the focus to a field of an object. */ export const focusObjectOn: { diff --git a/packages/effect-lens/src/Subscribable.ts b/packages/effect-lens/src/Subscribable.ts index c2ac183..9e6d107 100644 --- a/packages/effect-lens/src/Subscribable.ts +++ b/packages/effect-lens/src/Subscribable.ts @@ -40,6 +40,22 @@ export const mapOptionEffect: { onNone: () => Effect.succeed(Option.none()), }))) +/** + * Combines the current values and streams of changes from multiple `Subscribable` values. + */ +export const zipLatestAll = []>( + ...elements: T +): Subscribable.Subscribable< + [T[number]] extends [never] + ? never + : { [K in keyof T]: T[K] extends Subscribable.Subscribable ? A : never }, + [T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable ? E : never, + [T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable ? R : never +> => Subscribable.make({ + get: Effect.all(elements.map(view => view.get)), + changes: Stream.zipLatestAll(...elements.map(view => view.changes)), +}) as any + /** * Maps errors from both the current value and the stream of changes.