diff --git a/.changeset/spicy-tigers-dig.md b/.changeset/spicy-tigers-dig.md new file mode 100644 index 00000000000..d67a88d9208 --- /dev/null +++ b/.changeset/spicy-tigers-dig.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Improve `Predicate.all` and `Predicate.some` to support heterogeneous collections diff --git a/packages/effect/src/Array.ts b/packages/effect/src/Array.ts index 7898c4f4a84..1774e11a73b 100644 --- a/packages/effect/src/Array.ts +++ b/packages/effect/src/Array.ts @@ -12,7 +12,7 @@ import { dual, identity } from "./Function.js" import type { TypeLambda } from "./HKT.js" import * as internalArray from "./internal/array.js" import * as internalDoNotation from "./internal/doNotation.js" -import * as moduleIterable from "./Iterable.js" +import * as Iterable_ from "./Iterable.js" import * as Option from "./Option.js" import * as Order from "./Order.js" import * as Predicate from "./Predicate.js" @@ -1057,7 +1057,7 @@ export const findFirst: { (self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option (self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option -} = moduleIterable.findFirst +} = Iterable_.findFirst /** * Finds the last element in an iterable collection that satisfies the given predicate or refinement. @@ -2441,8 +2441,7 @@ export declare namespace ReadonlyArray { * @since 2.0.0 */ export type Infer> = S extends ReadonlyArray ? A - : S extends Iterable ? A - : never + : Iterable_.Iterable.Infer /** * @since 2.0.0 diff --git a/packages/effect/src/Iterable.ts b/packages/effect/src/Iterable.ts index ef6e742818c..5b1e74318fd 100644 --- a/packages/effect/src/Iterable.ts +++ b/packages/effect/src/Iterable.ts @@ -16,6 +16,29 @@ import type * as Record from "./Record.js" import * as Tuple from "./Tuple.js" import type { NoInfer } from "./Types.js" +/** + * @since 3.8.14 + */ +export declare namespace Iterable { + /** + * @since 3.8.14 + */ + export type Infer> = S extends Iterable ? A + : never + + /** + * @since 3.8.14 + */ + export type Return> = S extends Iterable ? R + : never + + /** + * @since 3.8.14 + */ + export type Next> = S extends Iterable ? N + : never +} + /** * Return a `Iterable` with element `i` initialized with `f(i)`. * diff --git a/packages/effect/src/Predicate.ts b/packages/effect/src/Predicate.ts index 8dc69e08c90..b6c07679788 100644 --- a/packages/effect/src/Predicate.ts +++ b/packages/effect/src/Predicate.ts @@ -18,6 +18,7 @@ */ import { dual, isFunction as isFunction_ } from "./Function.js" import type { TypeLambda } from "./HKT.js" +import type { Iterable as Iterable_ } from "./Iterable.js" import type { TupleOf, TupleOfAtLeast } from "./Types.js" /** @@ -948,12 +949,19 @@ export const product = * * @category combining * @since 2.0.0 - * @see tuple for a more powerful, variadic version. */ -export const all = ( - collection: Iterable> -): Predicate> => { - return (as) => { +export const all: { + >( + collection: A + ): Refinement< + Array>>, + Array>> + > + >(collection: A): Predicate>>> +} = >( + collection: A +) => { + return (as: Array>>): as is Array>> => { let collectionIndex = 0 for (const p of collection) { if (collectionIndex >= as.length) { @@ -1395,7 +1403,18 @@ export const every = (collection: Iterable>): Predicate => (a * @since 2.0.0 * @see every */ -export const some = (collection: Iterable>): Predicate => (a) => { +export const some: { + >( + collection: A + ): Refinement< + Refinement.In>, + Refinement.Out> + > + >(collection: A): Predicate>> +} = >( + collection: A +) => +(a: Refinement.In>): a is Refinement.Out> => { for (const p of collection) { if (p(a)) { return true