UNPKG

effect

Version:

The missing standard library for TypeScript, for writing production-grade software.

1,467 lines 921 kB
/** * @since 2.0.0 */ import type * as RA from "./Array.js"; import type * as Cause from "./Cause.js"; import type * as Chunk from "./Chunk.js"; import type * as Clock from "./Clock.js"; import type { ConfigProvider } from "./ConfigProvider.js"; import type { Console } from "./Console.js"; import type * as Context from "./Context.js"; import type * as Deferred from "./Deferred.js"; import type * as Duration from "./Duration.js"; import type * as Either from "./Either.js"; import type { Equivalence } from "./Equivalence.js"; import type { ExecutionStrategy } from "./ExecutionStrategy.js"; import type * as Exit from "./Exit.js"; import type * as Fiber from "./Fiber.js"; import type * as FiberId from "./FiberId.js"; import type * as FiberRef from "./FiberRef.js"; import type * as FiberRefs from "./FiberRefs.js"; import type * as FiberRefsPatch from "./FiberRefsPatch.js"; import type * as FiberStatus from "./FiberStatus.js"; import type { LazyArg } from "./Function.js"; import type * as HashMap from "./HashMap.js"; import type * as HashSet from "./HashSet.js"; import type { TypeLambda } from "./HKT.js"; import type * as Layer from "./Layer.js"; import type * as LogLevel from "./LogLevel.js"; import type * as ManagedRuntime from "./ManagedRuntime.js"; import type * as Metric from "./Metric.js"; import type * as MetricLabel from "./MetricLabel.js"; import type * as Option from "./Option.js"; import type { Pipeable } from "./Pipeable.js"; import type { Predicate, Refinement } from "./Predicate.js"; import type * as Random from "./Random.js"; import type * as Ref from "./Ref.js"; import * as Request from "./Request.js"; import type { RequestBlock } from "./RequestBlock.js"; import type { RequestResolver } from "./RequestResolver.js"; import type * as Runtime from "./Runtime.js"; import type * as RuntimeFlags from "./RuntimeFlags.js"; import type * as RuntimeFlagsPatch from "./RuntimeFlagsPatch.js"; import type * as Schedule from "./Schedule.js"; import * as Scheduler from "./Scheduler.js"; import type * as Scope from "./Scope.js"; import type * as Supervisor from "./Supervisor.js"; import type * as Tracer from "./Tracer.js"; import type { Concurrency, Contravariant, Covariant, NoExcessProperties, NoInfer, NotFunction } from "./Types.js"; import type * as Unify from "./Unify.js"; import { type YieldWrap } from "./Utils.js"; /** * @since 2.0.0 * @category Symbols */ export declare const EffectTypeId: unique symbol; /** * @since 2.0.0 * @category Symbols */ export type EffectTypeId = typeof EffectTypeId; /** * The `Effect` interface defines a value that describes a workflow or job, * which can succeed or fail. * * **Details** * * The `Effect` interface represents a computation that can model a workflow * involving various types of operations, such as synchronous, asynchronous, * concurrent, and parallel interactions. It operates within a context of type * `R`, and the result can either be a success with a value of type `A` or a * failure with an error of type `E`. The `Effect` is designed to handle complex * interactions with external resources, offering advanced features such as * fiber-based concurrency, scheduling, interruption handling, and scalability. * This makes it suitable for tasks that require fine-grained control over * concurrency and error management. * * To execute an `Effect` value, you need a `Runtime`, which provides the * environment necessary to run and manage the computation. * * @since 2.0.0 * @category Models */ export interface Effect<out A, out E = never, out R = never> extends Effect.Variance<A, E, R>, Pipeable { readonly [Unify.typeSymbol]?: unknown; readonly [Unify.unifySymbol]?: EffectUnify<this>; readonly [Unify.ignoreSymbol]?: EffectUnifyIgnore; [Symbol.iterator](): EffectGenerator<Effect<A, E, R>>; } /** * @since 3.0.0 * @category Models */ export interface EffectGenerator<T extends Effect<any, any, any>> { next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Effect.Success<T>>; } /** * @since 2.0.0 * @category Models */ export interface EffectUnify<A extends { [Unify.typeSymbol]?: any; }> extends Either.EitherUnify<A>, Option.OptionUnify<A>, Context.TagUnify<A> { Effect?: () => A[Unify.typeSymbol] extends Effect<infer A0, infer E0, infer R0> | infer _ ? Effect<A0, E0, R0> : never; } /** * @category Models * @since 2.0.0 */ export interface EffectUnifyIgnore { Tag?: true; Option?: true; Either?: true; } /** * @category Type lambdas * @since 2.0.0 */ export interface EffectTypeLambda extends TypeLambda { readonly type: Effect<this["Target"], this["Out1"], this["Out2"]>; } /** * @since 2.0.0 * @category Models */ export interface Blocked<out A, out E> extends Effect<A, E> { readonly _op: "Blocked"; readonly effect_instruction_i0: RequestBlock; readonly effect_instruction_i1: Effect<A, E>; } /** * @since 2.0.0 * @category Models */ declare module "./Context.js" { interface Tag<Id, Value> extends Effect<Value, never, Id> { [Symbol.iterator](): EffectGenerator<Tag<Id, Value>>; } interface Reference<Id, Value> extends Effect<Value> { [Symbol.iterator](): EffectGenerator<Reference<Id, Value>>; } interface TagUnifyIgnore { Effect?: true; Either?: true; Option?: true; } } /** * @since 2.0.0 * @category Models */ declare module "./Either.js" { interface Left<L, R> extends Effect<R, L> { readonly _tag: "Left"; [Symbol.iterator](): EffectGenerator<Left<L, R>>; } interface Right<L, R> extends Effect<R, L> { readonly _tag: "Right"; [Symbol.iterator](): EffectGenerator<Right<L, R>>; } interface EitherUnifyIgnore { Effect?: true; Tag?: true; Option?: true; } } /** * @since 2.0.0 * @category Models */ declare module "./Option.js" { interface None<A> extends Effect<A, Cause.NoSuchElementException> { readonly _tag: "None"; [Symbol.iterator](): EffectGenerator<None<A>>; } interface Some<A> extends Effect<A, Cause.NoSuchElementException> { readonly _tag: "Some"; [Symbol.iterator](): EffectGenerator<Some<A>>; } interface OptionUnifyIgnore { Effect?: true; Tag?: true; Either?: true; } } /** * @since 2.0.0 */ export declare namespace Effect { /** * @since 2.0.0 * @category Models */ interface Variance<out A, out E, out R> { readonly [EffectTypeId]: VarianceStruct<A, E, R>; } /** * @since 2.0.0 * @category Models */ interface VarianceStruct<out A, out E, out R> { readonly _V: string; readonly _A: Covariant<A>; readonly _E: Covariant<E>; readonly _R: Covariant<R>; } /** * @since 2.0.0 * @category Effect Type Extractors */ type Context<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _R : never; /** * @since 2.0.0 * @category Effect Type Extractors */ type Error<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _E : never; /** * @since 2.0.0 * @category Effect Type Extractors */ type Success<T extends Effect<any, any, any>> = [T] extends [Effect<infer _A, infer _E, infer _R>] ? _A : never; } /** * Checks if a given value is an `Effect` value. * * **When to Use** * * This function can be useful for checking the type of a value before * attempting to operate on it as an `Effect` value. For example, you could use * `Effect.isEffect` to check the type of a value before using it as an argument * to a function that expects an `Effect` value. * * @since 2.0.0 * @category Guards */ export declare const isEffect: (u: unknown) => u is Effect<unknown, unknown, unknown>; /** * Returns an effect that caches its result for a specified `Duration`, * known as "timeToLive" (TTL). * * **Details** * * This function is used to cache the result of an effect for a specified amount * of time. This means that the first time the effect is evaluated, its result * is computed and stored. * * If the effect is evaluated again within the specified `timeToLive`, the * cached result will be used, avoiding recomputation. * * After the specified duration has passed, the cache expires, and the effect * will be recomputed upon the next evaluation. * * **When to Use** * * Use this function when you have an effect that involves costly operations or * computations, and you want to avoid repeating them within a short time frame. * * It's ideal for scenarios where the result of an effect doesn't change * frequently and can be reused for a specified duration. * * By caching the result, you can improve efficiency and reduce unnecessary * computations, especially in performance-critical applications. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* Effect.sleep("100 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ export declare const cachedWithTTL: { /** * Returns an effect that caches its result for a specified `Duration`, * known as "timeToLive" (TTL). * * **Details** * * This function is used to cache the result of an effect for a specified amount * of time. This means that the first time the effect is evaluated, its result * is computed and stored. * * If the effect is evaluated again within the specified `timeToLive`, the * cached result will be used, avoiding recomputation. * * After the specified duration has passed, the cache expires, and the effect * will be recomputed upon the next evaluation. * * **When to Use** * * Use this function when you have an effect that involves costly operations or * computations, and you want to avoid repeating them within a short time frame. * * It's ideal for scenarios where the result of an effect doesn't change * frequently and can be reused for a specified duration. * * By caching the result, you can improve efficiency and reduce unnecessary * computations, especially in performance-critical applications. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* Effect.sleep("100 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ (timeToLive: Duration.DurationInput): <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<A, E>, never, R>; /** * Returns an effect that caches its result for a specified `Duration`, * known as "timeToLive" (TTL). * * **Details** * * This function is used to cache the result of an effect for a specified amount * of time. This means that the first time the effect is evaluated, its result * is computed and stored. * * If the effect is evaluated again within the specified `timeToLive`, the * cached result will be used, avoiding recomputation. * * After the specified duration has passed, the cache expires, and the effect * will be recomputed upon the next evaluation. * * **When to Use** * * Use this function when you have an effect that involves costly operations or * computations, and you want to avoid repeating them within a short time frame. * * It's ideal for scenarios where the result of an effect doesn't change * frequently and can be reused for a specified duration. * * By caching the result, you can improve efficiency and reduce unnecessary * computations, especially in performance-critical applications. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* Effect.sleep("100 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ <A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<Effect<A, E>, never, R>; }; /** * Caches an effect's result for a specified duration and allows manual * invalidation before expiration. * * **Details** * * This function behaves similarly to {@link cachedWithTTL} by caching the * result of an effect for a specified period of time. However, it introduces an * additional feature: it provides an effect that allows you to manually * invalidate the cached result before it naturally expires. * * This gives you more control over the cache, allowing you to refresh the * result when needed, even if the original cache has not yet expired. * * Once the cache is invalidated, the next time the effect is evaluated, the * result will be recomputed, and the cache will be refreshed. * * **When to Use** * * Use this function when you have an effect whose result needs to be cached for * a certain period, but you also want the option to refresh the cache manually * before the expiration time. * * This is useful when you need to ensure that the cached data remains valid for * a certain period but still want to invalidate it if the underlying data * changes or if you want to force a recomputation. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedWithTTL} for a similar function that caches the result for * a specified duration but does not include an effect for manual invalidation. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( * expensiveTask, * "1 hour" * ) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* invalidate * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ export declare const cachedInvalidateWithTTL: { /** * Caches an effect's result for a specified duration and allows manual * invalidation before expiration. * * **Details** * * This function behaves similarly to {@link cachedWithTTL} by caching the * result of an effect for a specified period of time. However, it introduces an * additional feature: it provides an effect that allows you to manually * invalidate the cached result before it naturally expires. * * This gives you more control over the cache, allowing you to refresh the * result when needed, even if the original cache has not yet expired. * * Once the cache is invalidated, the next time the effect is evaluated, the * result will be recomputed, and the cache will be refreshed. * * **When to Use** * * Use this function when you have an effect whose result needs to be cached for * a certain period, but you also want the option to refresh the cache manually * before the expiration time. * * This is useful when you need to ensure that the cached data remains valid for * a certain period but still want to invalidate it if the underlying data * changes or if you want to force a recomputation. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedWithTTL} for a similar function that caches the result for * a specified duration but does not include an effect for manual invalidation. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( * expensiveTask, * "1 hour" * ) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* invalidate * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ (timeToLive: Duration.DurationInput): <A, E, R>(self: Effect<A, E, R>) => Effect<[Effect<A, E>, Effect<void>], never, R>; /** * Caches an effect's result for a specified duration and allows manual * invalidation before expiration. * * **Details** * * This function behaves similarly to {@link cachedWithTTL} by caching the * result of an effect for a specified period of time. However, it introduces an * additional feature: it provides an effect that allows you to manually * invalidate the cached result before it naturally expires. * * This gives you more control over the cache, allowing you to refresh the * result when needed, even if the original cache has not yet expired. * * Once the cache is invalidated, the next time the effect is evaluated, the * result will be recomputed, and the cache will be refreshed. * * **When to Use** * * Use this function when you have an effect whose result needs to be cached for * a certain period, but you also want the option to refresh the cache manually * before the expiration time. * * This is useful when you need to ensure that the cached data remains valid for * a certain period but still want to invalidate it if the underlying data * changes or if you want to force a recomputation. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedWithTTL} for a similar function that caches the result for * a specified duration but does not include an effect for manual invalidation. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( * expensiveTask, * "1 hour" * ) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* invalidate * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ <A, E, R>(self: Effect<A, E, R>, timeToLive: Duration.DurationInput): Effect<[Effect<A, E>, Effect<void>], never, R>; }; /** * Returns an effect that lazily computes a result and caches it for subsequent * evaluations. * * **Details** * * This function wraps an effect and ensures that its result is computed only * once. Once the result is computed, it is cached, meaning that subsequent * evaluations of the same effect will return the cached result without * re-executing the logic. * * **When to Use** * * Use this function when you have an expensive or time-consuming operation that * you want to avoid repeating. The first evaluation will compute the result, * and all following evaluations will immediately return the cached value, * improving performance and reducing unnecessary work. * * @see {@link cachedWithTTL} for a similar function that includes a * time-to-live duration for the cached value. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * console.log("non-cached version:") * yield* expensiveTask.pipe(Effect.andThen(Console.log)) * yield* expensiveTask.pipe(Effect.andThen(Console.log)) * console.log("cached version:") * const cached = yield* Effect.cached(expensiveTask) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // non-cached version: * // expensive task... * // result 1 * // expensive task... * // result 2 * // cached version: * // expensive task... * // result 3 * // result 3 * ``` * * @since 2.0.0 * @category Caching */ export declare const cached: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<A, E, R>>; /** * Returns a memoized version of a function with effects, reusing results for * the same inputs. * * **Details** * * This function creates a memoized version of a given function that performs an * effect. Memoization ensures that once a result is computed for a specific * input, it is stored and reused for subsequent calls with the same input, * reducing the need to recompute the result. * * The function can optionally take an `Equivalence` parameter to * determine how inputs are compared for caching purposes. * * **When to Use** * * Use this function when you have a function that performs an effect and you * want to avoid recomputing the result for the same input multiple times. * * It's ideal for functions that produce deterministic results based on their * inputs, and you want to improve performance by caching the output. * * This is particularly useful in scenarios where the function involves * expensive calculations or operations that should be avoided after the first * execution with the same parameters. * * @example * ```ts * import { Effect, Random } from "effect" * * const program = Effect.gen(function* () { * const randomNumber = (n: number) => Random.nextIntBetween(1, n) * console.log("non-memoized version:") * console.log(yield* randomNumber(10)) * console.log(yield* randomNumber(10)) * * console.log("memoized version:") * const memoized = yield* Effect.cachedFunction(randomNumber) * console.log(yield* memoized(10)) * console.log(yield* memoized(10)) * }) * * // Effect.runFork(program) * // Example Output: * // non-memoized version: * // 2 * // 8 * // memoized version: * // 5 * // 5 * ``` * * @since 2.0.0 * @category Caching */ export declare const cachedFunction: <A, B, E, R>(f: (a: A) => Effect<B, E, R>, eq?: Equivalence<A>) => Effect<(a: A) => Effect<B, E, R>>; /** * Returns an effect that executes only once, regardless of how many times it's * called. * * **Details** * * This function ensures that a specific effect is executed only a single time, * no matter how many times it is invoked. The result of the effect will be * cached, and subsequent calls to the effect will immediately return the cached * result without re-executing the original logic. * * **When to Use** * * Use this function when you need to perform a task only once, regardless of * how many times the effect is triggered. It's particularly useful when you * have initialization tasks, logging, or other one-time actions that should not * be repeated. This can help optimize performance and avoid redundant actions. * * @example * ```ts * import { Effect, Console } from "effect" * * const program = Effect.gen(function* () { * const task1 = Console.log("task1") * yield* Effect.repeatN(task1, 2) * const task2 = yield* Effect.once(Console.log("task2")) * yield* Effect.repeatN(task2, 2) * }) * * // Effect.runFork(program) * // Output: * // task1 * // task1 * // task1 * // task2 * ``` * * @since 2.0.0 * @category Caching */ export declare const once: <A, E, R>(self: Effect<A, E, R>) => Effect<Effect<void, E, R>>; /** * Combines multiple effects into one, returning results based on the input * structure. * * **Details** * * Use this function when you need to run multiple effects and combine their * results into a single output. It supports tuples, iterables, structs, and * records, making it flexible for different input types. * * For instance, if the input is a tuple: * * ```ts * // ┌─── a tuple of effects * // ▼ * Effect.all([effect1, effect2, ...]) * ``` * * the effects are executed sequentially, and the result is a new effect * containing the results as a tuple. The results in the tuple match the order * of the effects passed to `Effect.all`. * * **Concurrency** * * You can control the execution order (e.g., sequential vs. concurrent) using * the `concurrency` option. * * **Short-Circuiting Behavior** * * This function stops execution on the first error it encounters, this is * called "short-circuiting". If any effect in the collection fails, the * remaining effects will not run, and the error will be propagated. To change * this behavior, you can use the `mode` option, which allows all effects to run * and collect results as `Either` or `Option`. * * **The `mode` option** * * The `{ mode: "either" }` option changes the behavior of `Effect.all` to * ensure all effects run, even if some fail. Instead of stopping on the first * failure, this mode collects both successes and failures, returning an array * of `Either` instances where each result is either a `Right` (success) or a * `Left` (failure). * * Similarly, the `{ mode: "validate" }` option uses `Option` to indicate * success or failure. Each effect returns `None` for success and `Some` with * the error for failure. * * @see {@link forEach} for iterating over elements and applying an effect. * @see {@link allWith} for a data-last version of this function. * * @example * ```ts * // Title: Combining Effects in Tuples * import { Effect, Console } from "effect" * * const tupleOfEffects = [ * Effect.succeed(42).pipe(Effect.tap(Console.log)), * Effect.succeed("Hello").pipe(Effect.tap(Console.log)) * ] as const * * // ┌─── Effect<[number, string], never, never> * // ▼ * const resultsAsTuple = Effect.all(tupleOfEffects) * * // Effect.runPromise(resultsAsTuple).then(console.log) * // Output: * // 42 * // Hello * // [ 42, 'Hello' ] * ``` * * @example * // Title: Combining Effects in Iterables * import { Effect, Console } from "effect" * * const iterableOfEffects: Iterable<Effect.Effect<number>> = [1, 2, 3].map( * (n) => Effect.succeed(n).pipe(Effect.tap(Console.log)) * ) * * // ┌─── Effect<number[], never, never> * // ▼ * const resultsAsArray = Effect.all(iterableOfEffects) * * // Effect.runPromise(resultsAsArray).then(console.log) * // Output: * // 1 * // 2 * // 3 * // [ 1, 2, 3 ] * * @example * // Title: Combining Effects in Structs * import { Effect, Console } from "effect" * * const structOfEffects = { * a: Effect.succeed(42).pipe(Effect.tap(Console.log)), * b: Effect.succeed("Hello").pipe(Effect.tap(Console.log)) * } * * // ┌─── Effect<{ a: number; b: string; }, never, never> * // ▼ * const resultsAsStruct = Effect.all(structOfEffects) * * // Effect.runPromise(resultsAsStruct).then(console.log) * // Output: * // 42 * // Hello * // { a: 42, b: 'Hello' } * * @example * // Title: Combining Effects in Records * import { Effect, Console } from "effect" * * const recordOfEffects: Record<string, Effect.Effect<number>> = { * key1: Effect.succeed(1).pipe(Effect.tap(Console.log)), * key2: Effect.succeed(2).pipe(Effect.tap(Console.log)) * } * * // ┌─── Effect<{ [x: string]: number; }, never, never> * // ▼ * const resultsAsRecord = Effect.all(recordOfEffects) * * // Effect.runPromise(resultsAsRecord).then(console.log) * // Output: * // 1 * // 2 * // { key1: 1, key2: 2 } * * @example * // Title: Short-Circuiting Behavior * import { Effect, Console } from "effect" * * const program = Effect.all([ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * // Won't execute due to earlier failure * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ]) * * // Effect.runPromiseExit(program).then(console.log) * // Output: * // Task1 * // { * // _id: 'Exit', * // _tag: 'Failure', * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' } * // } * * @example * // Title: Collecting Results with `mode: "either"` * import { Effect, Console } from "effect" * * const effects = [ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ] * * const program = Effect.all(effects, { mode: "either" }) * * // Effect.runPromiseExit(program).then(console.log) * // Output: * // Task1 * // Task3 * // { * // _id: 'Exit', * // _tag: 'Success', * // value: [ * // { _id: 'Either', _tag: 'Right', right: 'Task1' }, * // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' }, * // { _id: 'Either', _tag: 'Right', right: 'Task3' } * // ] * // } * * @example * //Example: Collecting Results with `mode: "validate"` * import { Effect, Console } from "effect" * * const effects = [ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ] * * const program = Effect.all(effects, { mode: "validate" }) * * // Effect.runPromiseExit(program).then((result) => console.log("%o", result)) * // Output: * // Task1 * // Task3 * // { * // _id: 'Exit', * // _tag: 'Failure', * // cause: { * // _id: 'Cause', * // _tag: 'Fail', * // failure: [ * // { _id: 'Option', _tag: 'None' }, * // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' }, * // { _id: 'Option', _tag: 'None' } * // ] * // } * // } * * @since 2.0.0 * @category Collecting */ export declare const all: <const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>, O extends { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined; readonly discard?: boolean | undefined; readonly mode?: "default" | "validate" | "either" | undefined; readonly concurrentFinalizers?: boolean | undefined; }>(arg: Arg, options?: O) => All.Return<Arg, O>; /** * A data-last version of {@link all}, designed for use in pipelines. * * **When to Use** * * This function enables you to combine multiple effects and customize execution * options such as concurrency levels. This version is useful in functional * pipelines where you first define your data and then apply operations to it. * * @example * ```ts * import { Effect, pipe } from "effect" * * const task1 = Effect.succeed(1).pipe( * Effect.delay("200 millis"), * Effect.tap(Effect.log("task1 done")) * ) * * const task2 = Effect.succeed("hello").pipe( * Effect.delay("100 millis"), * Effect.tap(Effect.log("task2 done")) * ) * * const program = pipe( * [task1, task2], * // Run both effects concurrently using the concurrent option * Effect.allWith({ concurrency: 2 }) * ) * * // Effect.runPromise(program).then(console.log) * // Output: * // timestamp=... level=INFO fiber=#3 message="task2 done" * // timestamp=... level=INFO fiber=#2 message="task1 done" * // [ 1, 'hello' ] * ``` * * @since 2.0.0 * @category Collecting */ export declare const allWith: <O extends { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined; readonly discard?: boolean | undefined; readonly mode?: "default" | "validate" | "either" | undefined; readonly concurrentFinalizers?: boolean | undefined; }>(options?: O) => <const Arg extends Iterable<Effect<any, any, any>> | Record<string, Effect<any, any, any>>>(arg: Arg) => All.Return<Arg, O>; /** * @since 2.0.0 */ export declare namespace All { /** * @since 2.0.0 */ type EffectAny = Effect<any, any, any>; /** * @since 2.0.0 */ type ReturnIterable<T extends Iterable<EffectAny>, Discard extends boolean, Mode> = [T] extends [ Iterable<Effect.Variance<infer R0, infer L0, infer R>> ] ? Effect<Discard extends true ? void : Mode extends "either" ? Array<Either.Either<R0, L0>> : Array<R0>, Mode extends "either" ? never : Mode extends "validate" ? Array<Option.Option<L0>> : L0, R> : never; /** * @since 2.0.0 */ type ReturnTuple<T extends ReadonlyArray<unknown>, Discard extends boolean, Mode> = Effect<Discard extends true ? void : T[number] extends never ? [] : Mode extends "either" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Either.Either<_A, _E> : never; } : { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? _A : never; }, Mode extends "either" ? never : T[number] extends never ? never : Mode extends "validate" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Option.Option<_E> : never; } : [T[number]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E; }; }] ? E : never, T[number] extends never ? never : [T[number]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R; }; }] ? R : never> extends infer X ? X : never; /** * @since 2.0.0 */ type ReturnObject<T, Discard extends boolean, Mode> = [T] extends [{ [K: string]: EffectAny; }] ? Effect<Discard extends true ? void : Mode extends "either" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Either.Either<_A, _E> : never; } : { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? _A : never; }, Mode extends "either" ? never : keyof T extends never ? never : Mode extends "validate" ? { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance<infer _A, infer _E, infer _R>] ? Option.Option<_E> : never; } : [T[keyof T]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E; }; }] ? E : never, keyof T extends never ? never : [T[keyof T]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R; }; }] ? R : never> : never; /** * @since 2.0.0 */ type IsDiscard<A> = [Extract<A, { readonly discard: true; }>] extends [never] ? false : true; /** * @since 2.0.0 */ type ExtractMode<A> = [A] extends [{ mode: infer M; }] ? M : "default"; /** * @since 2.0.0 */ type Return<Arg extends Iterable<EffectAny> | Record<string, EffectAny>, O extends { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined; readonly discard?: boolean | undefined; readonly mode?: "default" | "validate" | "either" | undefined; readonly concurrentFinalizers?: boolean | undefined; }> = [Arg] extends [ReadonlyArray<EffectAny>] ? ReturnTuple<Arg, IsDiscard<O>, ExtractMode<O>> : [Arg] extends [Iterable<EffectAny>] ? ReturnIterable<Arg, IsDiscard<O>, ExtractMode<O>> : [Arg] extends [Record<string, EffectAny>] ? ReturnObject<Arg, IsDiscard<O>, ExtractMode<O>> : never; } /** * Evaluates and runs each effect in the iterable, collecting only the * successful results while discarding failures. * * **Details** * * This function function processes an iterable of effects and runs each one. If * an effect is successful, its result is collected; if it fails, the result is * discarded. This ensures that only successful outcomes are kept. * * **Options** * * The function also allows you to customize how the effects are handled by * specifying options such as concurrency, batching, and how finalizers behave. * These options provide flexibility in running the effects concurrently or * adjusting other execution details. * * @example * ```ts * import { Effect } from "effect" * * const tasks = [ * Effect.succeed(1), * Effect.fail("Error 1"), * Effect.succeed(2), * Effect.fail("Error 2") * ] * * const program = Effect.gen(function*() { * const successfulResults = yield* Effect.allSuccesses(tasks) * console.log(successfulResults) * }) * * // Effect.runFork(program) * // Output: [1, 2] * * ``` * * @since 2.0.0 * @category Collecting */ export declare const allSuccesses: <X extends Effect<any, any, any>>(elements: Iterable<X>, options?: { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined; readonly concurrentFinalizers?: boolean | undefined; } | undefined) => Effect<Array<Effect.Success<X>>, never, Effect.Context<X>>; /** * Drops elements until the effectful predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to determine when to stop dropping elements. It drops elements from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection and returns an effect that evaluates to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are returned. * * **Note**: The first element for which the predicate returns `true` is also * dropped. * * **When to Use** * * This function allows you to conditionally skip over a part of the collection * based on some criteria defined in the predicate. * * @see {@link dropWhile} for a similar function that drops elements while the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropUntil(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [5, 6] * ``` * * @since 2.0.0 * @category Collecting */ export declare const dropUntil: { /** * Drops elements until the effectful predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to determine when to stop dropping elements. It drops elements from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection and returns an effect that evaluates to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are returned. * * **Note**: The first element for which the predicate returns `true` is also * dropped. * * **When to Use** * * This function allows you to conditionally skip over a part of the collection * based on some criteria defined in the predicate. * * @see {@link dropWhile} for a similar function that drops elements while the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropUntil(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [5, 6] * ``` * * @since 2.0.0 * @category Collecting */ <A, E, R>(predicate: (a: NoInfer<A>, i: number) => Effect<boolean, E, R>): (elements: Iterable<A>) => Effect<Array<A>, E, R>; /** * Drops elements until the effectful predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to determine when to stop dropping elements. It drops elements from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection and returns an effect that evaluates to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are returned. * * **Note**: The first element for which the predicate returns `true` is also * dropped. * * **When to Use** * * This function allows you to conditionally skip over a part of the collection * based on some criteria defined in the predicate. * * @see {@link dropWhile} for a similar function that drops elements while the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropUntil(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [5, 6] * ``` * * @since 2.0.0 * @category Collecting */ <A, E, R>(elements: Iterable<A>, predicate: (a: A, i: number) => Effect<boolean, E, R>): Effect<Array<A>, E, R>; }; /** * Drops elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to drop an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be dropped * from the collection. * * Once the predicate returns `false`, the remaining elements are kept. * * **When to Use** * * This function allows you to discard elements from the start of a collection * based on a condition, and only keep the rest when the condition no longer * holds. * * @see {@link dropUntil} for a similar function that drops elements until the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropWhile(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [4, 5, 6] * ``` * * @since 2.0.0 * @category Collecting */ export declare const dropWhile: { /** * Drops elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to drop an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be dropped * from the collection. * * Once the predicate returns `false`, the remaining elements are kept. * * **When to Use** * * This function allows you to discard elements from the start of a collection * based on a condition, and only keep the rest when the condition no longer * holds. * * @see {@link dropUntil} for a similar function that drops elements until the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropWhile(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [4, 5, 6] * ``` * * @since 2.0.0 * @category Collecting */ <A, E, R>(predicate: (a: NoInfer<A>, i: number) => Effect<boolean, E, R>): (elements: Iterable<A>) => Effect<Array<A>, E, R>; /** * Drops elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to drop an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be dropped * from the collection. * * Once the predicate returns `false`, the remaining elements are kept. * * **When to Use** * * This function allows you to discard elements from the start of a collection * based on a condition, and only keep the rest when the condition no longer * holds. * * @see {@link dropUntil} for a similar function that drops elements until the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropWhile(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [4, 5, 6] * ``` * * @since 2.0.0 * @category Collecting */ <A, E, R>(elements: Iterable<A>, predicate: (a: A, i: number) => Effect<boolean, E, R>): Effect<Array<A>, E, R>; }; /** * Takes elements from a collection until the effectful predicat