Skip to content

Error Channel Operations

In Effect you can perform various operations on the error channel of effects. These operations allow you to transform, inspect, and handle errors in different ways. Let’s explore some of these operations.

The Effect.mapError function is used when you need to transform or modify an error produced by an effect, without affecting the success value. This can be helpful when you want to add extra information to the error or change its type.

Example (Mapping an Error)

Here, the error type changes from string to Error.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// ┌─── Effect<number, string, never>
// ▼
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh no!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

as allows you to ignore the original value inside an effect and replace it with a new constant value.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(1))
// ┌─── Effect<number, Error, never>
// ▼
const
const mapped: Effect.Effect<number, Error, never>
mapped
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const mapError: <number, string, never, Error>(self: Effect.Effect<number, string, never>, f: (e: string) => Error) => Effect.Effect<number, Error, never> (+1 overload)

The mapError function is used to transform or modify the error produced by an effect, without affecting its success value.

This function is helpful when you want to enhance the error with additional information, change the error type, or apply custom error handling while keeping the original behavior of the effect's success values intact. It only operates on the error channel and leaves the success channel unchanged.

@seemap for a version that operates on the success channel.

@seemapBoth for a version that operates on both channels.

@seeorElseFail if you want to replace the error with a new one.

@example

import { Effect } from "effect"
// ┌─── Effect<number, string, never>
// ▼
const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1))
// ┌─── Effect<number, Error, never>
// ▼
const mapped = Effect.mapError(
simulatedTask,
(message) => new Error(message)
)

@since2.0.0

mapError
(
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
,
(
message: string
message
) => new
var Error: ErrorConstructor
new (message?: string) => Error
Error
(
message: string
message
)
)

The Effect.mapBoth function allows you to apply transformations to both channels: the error channel and the success channel of an effect. It takes two map functions as arguments: one for the error channel and the other for the success channel.

Example (Mapping Both Success and Error)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// ┌─── Effect<number, string, never>
// ▼
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh no!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

as allows you to ignore the original value inside an effect and replace it with a new constant value.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(1))
// ┌─── Effect<boolean, Error, never>
// ▼
const
const modified: Effect.Effect<boolean, Error, never>
modified
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const mapBoth: <number, string, never, Error, boolean>(self: Effect.Effect<number, string, never>, options: {
readonly onFailure: (e: string) => Error;
readonly onSuccess: (a: number) => boolean;
}) => Effect.Effect<...> (+1 overload)

The mapBoth function allows you to apply transformations to both the error and success channels of an effect.

This function takes two map functions as arguments: one for the error channel and one for the success channel. You can use it when you want to modify both the error and the success values without altering the overall success or failure status of the effect.

@seemap for a version that operates on the success channel.

@seemapError for a version that operates on the error channel.

@example

import { Effect } from "effect"
// ┌─── Effect<number, string, never>
// ▼
const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1))
// ┌─── Effect<boolean, Error, never>
// ▼
const modified = Effect.mapBoth(simulatedTask, {
onFailure: (message) => new Error(message),
onSuccess: (n) => n > 0
})

@since2.0.0

mapBoth
(
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
, {
onFailure: (e: string) => Error
onFailure
: (
message: string
message
) => new
var Error: ErrorConstructor
new (message?: string) => Error
Error
(
message: string
message
),
onSuccess: (a: number) => boolean
onSuccess
: (
n: number
n
) =>
n: number
n
> 0
})

The Effect library provides several operators to filter values on the success channel based on a given predicate.

These operators offer different strategies for handling cases where the predicate fails:

APIDescription
filterOrFailThis operator filters the values on the success channel based on a predicate. If the predicate fails for any value, the original effect fails with an error.
filterOrDie / filterOrDieMessageThese operators also filter the values on the success channel based on a predicate. If the predicate fails for any value, the original effect terminates abruptly. The filterOrDieMessage variant allows you to provide a custom error message.
filterOrElseThis operator filters the values on the success channel based on a predicate. If the predicate fails for any value, an alternative effect is executed instead.

Example (Filtering Success Values)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Random
Random
,
import Cause
Cause
} from "effect"
// Fail with a custom error if predicate is false
const
const task1: Effect.Effect<number, string, never>
task1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const filterOrFail: <number, never, never, string>(self: Effect.Effect<number, never, never>, predicate: Predicate<number>, orFailWith: (a: number) => string) => Effect.Effect<number, string, never> (+7 overloads)

Filter the specified effect with the provided function, failing with specified error if the predicate fails.

In addition to the filtering capabilities discussed earlier, you have the option to further refine and narrow down the type of the success channel by providing a user-defined type guard. Let's explore this concept through an example:

@example

import { Effect, pipe } from "effect"
// Define a user interface
interface User {
readonly name: string
}
// Simulate an asynchronous authentication function
declare const auth: () => Promise<User | null>
const program = pipe(
Effect.promise(() => auth()),
// Use filterOrFail with a custom type guard to ensure user is not null
Effect.filterOrFail(
(user): user is User => user !== null, // Type guard
() => new Error("Unauthorized")
),
// 'user' now has the type `User` (not `User | null`)
Effect.andThen((user) => user.name)
)

@since2.0.0

filterOrFail
(
import Random
Random
.
const nextRange: (min: number, max: number) => Effect.Effect<number>

Returns the next numeric value in the specified range from the pseudo-random number generator.

@since2.0.0

nextRange
(-1, 1),
(
n: number
n
) =>
n: number
n
>= 0,
() => "random number is negative"
)
// Die with a custom exception if predicate is false
const
const task2: Effect.Effect<number, never, never>
task2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const filterOrDie: <number, never, never>(self: Effect.Effect<number, never, never>, predicate: Predicate<number>, orDieWith: (a: number) => unknown) => Effect.Effect<number, never, never> (+3 overloads)

Filter the specified effect with the provided function, dying with specified defect if the predicate fails.

@since2.0.0

filterOrDie
(
import Random
Random
.
const nextRange: (min: number, max: number) => Effect.Effect<number>

Returns the next numeric value in the specified range from the pseudo-random number generator.

@since2.0.0

nextRange
(-1, 1),
(
n: number
n
) =>
n: number
n
>= 0,
() => new
import Cause
Cause
.
const IllegalArgumentException: new (message?: string | undefined) => Cause.IllegalArgumentException

Represents a checked exception which occurs when an invalid argument is provided to a method.

@since2.0.0

IllegalArgumentException
("random number is negative")
)
// Die with a custom error message if predicate is false
const
const task3: Effect.Effect<number, never, never>
task3
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const filterOrDieMessage: <number, never, never>(self: Effect.Effect<number, never, never>, predicate: Predicate<number>, message: string) => Effect.Effect<number, never, never> (+3 overloads)

Filter the specified effect with the provided function, dying with specified message if the predicate fails.

@since2.0.0

filterOrDieMessage
(
import Random
Random
.
const nextRange: (min: number, max: number) => Effect.Effect<number>

Returns the next numeric value in the specified range from the pseudo-random number generator.

@since2.0.0

nextRange
(-1, 1),
(
n: number
n
) =>
n: number
n
>= 0,
"random number is negative"
)
// Run an alternative effect if predicate is false
const
const task4: Effect.Effect<number, never, never>
task4
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const filterOrElse: <number, never, never, number, never, never>(self: Effect.Effect<number, never, never>, predicate: Predicate<number>, orElse: (a: number) => Effect.Effect<number, never, never>) => Effect.Effect<...> (+3 overloads)

Filters the specified effect with the provided function returning the value of the effect if it is successful, otherwise returns the value of orElse.

@since2.0.0

filterOrElse
(
import Random
Random
.
const nextRange: (min: number, max: number) => Effect.Effect<number>

Returns the next numeric value in the specified range from the pseudo-random number generator.

@since2.0.0

nextRange
(-1, 1),
(
n: number
n
) =>
n: number
n
>= 0,
() =>
const task3: Effect.Effect<number, never, never>
task3
)

It’s important to note that depending on the specific filtering operator used, the effect can either fail, terminate abruptly, or execute an alternative effect when the predicate fails. Choose the appropriate operator based on your desired error handling strategy and program logic.

The filtering APIs can also be combined with user-defined type guards to improve type safety and code clarity. This ensures that only valid types pass through.

Example (Using a Type Guard)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
function pipe<A>(a: A): A (+19 overloads)

Pipes the value of an expression into a pipeline of functions.

When to Use

This is useful in combination with data-last functions as a simulation of methods:

as.map(f).filter(g)

becomes:

import { pipe, Array } from "effect"
pipe(as, Array.map(f), Array.filter(g))

Details

The pipe function is a utility that allows us to compose functions in a readable and sequential manner. It takes the output of one function and passes it as the input to the next function in the pipeline. This enables us to build complex transformations by chaining multiple functions together.

import { pipe } from "effect"
const result = pipe(input, func1, func2, ..., funcN)

In this syntax, input is the initial value, and func1, func2, ..., funcN are the functions to be applied in sequence. The result of each function becomes the input for the next function, and the final result is returned.

Here's an illustration of how pipe works:

┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌────────┐
│ input │───►│ func1 │───►│ func2 │───►│ ... │───►│ funcN │───►│ result │
└───────┘ └───────┘ └───────┘ └───────┘ └───────┘ └────────┘

It's important to note that functions passed to pipe must have a single argument because they are only called with a single argument.

@example

// Example: Chaining Arithmetic Operations
import { pipe } from "effect"
// Define simple arithmetic operations
const increment = (x: number) => x + 1
const double = (x: number) => x * 2
const subtractTen = (x: number) => x - 10
// Sequentially apply these operations using `pipe`
const result = pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2

@since2.0.0

pipe
} from "effect"
// Define a user interface
interface
interface User
User
{
readonly
User.name: string
name
: string
}
// Simulate an asynchronous authentication function
declare const
const auth: () => Promise<User | null>
auth
: () =>
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<
interface User
User
| null>
const
const program: Effect.Effect<string, Error, never>
program
=
pipe<Effect.Effect<User | null, never, never>, Effect.Effect<User, Error, never>, Effect.Effect<string, Error, never>>(a: Effect.Effect<...>, ab: (a: Effect.Effect<...>) => Effect.Effect<...>, bc: (b: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+19 overloads)

Pipes the value of an expression into a pipeline of functions.

When to Use

This is useful in combination with data-last functions as a simulation of methods:

as.map(f).filter(g)

becomes:

import { pipe, Array } from "effect"
pipe(as, Array.map(f), Array.filter(g))

Details

The pipe function is a utility that allows us to compose functions in a readable and sequential manner. It takes the output of one function and passes it as the input to the next function in the pipeline. This enables us to build complex transformations by chaining multiple functions together.

import { pipe } from "effect"
const result = pipe(input, func1, func2, ..., funcN)

In this syntax, input is the initial value, and func1, func2, ..., funcN are the functions to be applied in sequence. The result of each function becomes the input for the next function, and the final result is returned.

Here's an illustration of how pipe works:

┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌────────┐
│ input │───►│ func1 │───►│ func2 │───►│ ... │───►│ funcN │───►│ result │
└───────┘ └───────┘ └───────┘ └───────┘ └───────┘ └────────┘

It's important to note that functions passed to pipe must have a single argument because they are only called with a single argument.

@example

// Example: Chaining Arithmetic Operations
import { pipe } from "effect"
// Define simple arithmetic operations
const increment = (x: number) => x + 1
const double = (x: number) => x * 2
const subtractTen = (x: number) => x - 10
// Sequentially apply these operations using `pipe`
const result = pipe(5, increment, double, subtractTen)
console.log(result)
// Output: 2

@since2.0.0

pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const promise: <User | null>(evaluate: (signal: AbortSignal) => PromiseLike<User | null>) => Effect.Effect<User | null, never, never>

Creates an Effect that represents an asynchronous computation guaranteed to succeed.

When to Use

Use promise when you are sure the operation will not reject.

Details

The provided function (thunk) returns a Promise that should never reject; if it does, the error will be treated as a "defect".

This defect is not a standard error but indicates a flaw in the logic that was expected to be error-free. You can think of it similar to an unexpected crash in the program, which can be further managed or logged using tools like

catchAllDefect

.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

@seetryPromise for a version that can handle failures.

@example

// Title: Delayed Message
import { Effect } from "effect"
const delay = (message: string) =>
Effect.promise<string>(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve(message)
}, 2000)
})
)
// ┌─── Effect<string, never, never>
// ▼
const program = delay("Async operation completed successfully!")

@since2.0.0

promise
(() =>
const auth: () => Promise<User | null>
auth
()),
// Use filterOrFail with a custom type guard to ensure user is not null
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const filterOrFail: <User | null, User, Error>(refinement: Refinement<User | null, User>, orFailWith: (a: User | null) => Error) => <E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+7 overloads)

Filter the specified effect with the provided function, failing with specified error if the predicate fails.

In addition to the filtering capabilities discussed earlier, you have the option to further refine and narrow down the type of the success channel by providing a user-defined type guard. Let's explore this concept through an example:

@example

import { Effect, pipe } from "effect"
// Define a user interface
interface User {
readonly name: string
}
// Simulate an asynchronous authentication function
declare const auth: () => Promise<User | null>
const program = pipe(
Effect.promise(() => auth()),
// Use filterOrFail with a custom type guard to ensure user is not null
Effect.filterOrFail(
(user): user is User => user !== null, // Type guard
() => new Error("Unauthorized")
),
// 'user' now has the type `User` (not `User | null`)
Effect.andThen((user) => user.name)
)

@since2.0.0

filterOrFail
(
(
user: User | null
user
):
user: User | null
user
is
interface User
User
=>
user: User | null
user
!== null, // Type guard
() => new
var Error: ErrorConstructor
new (message?: string) => Error
Error
("Unauthorized")
),
// 'user' now has the type `User` (not `User | null`)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const andThen: <User, string>(f: (a: User) => string) => <E, R>(self: Effect.Effect<User, E, R>) => Effect.Effect<string, E, R> (+3 overloads)

Chains two actions, where the second action can depend on the result of the first.

Syntax

const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect))
// or
const transformedEffect = Effect.andThen(myEffect, anotherEffect)
// or
const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect))

When to Use

Use andThen when you need to run multiple actions in sequence, with the second action depending on the result of the first. This is useful for combining effects or handling computations that must happen in order.

Details

The second action can be:

  • A constant value (similar to

as

)

  • A function returning a value (similar to

map

)

  • A Promise
  • A function returning a Promise
  • An Effect
  • A function returning an Effect (similar to

flatMap

)

Note: andThen works well with both Option and Either types, treating them as effects.

@example

// Title: Applying a Discount Based on Fetched Amount
import { pipe, Effect } from "effect"
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
// Using Effect.map and Effect.flatMap
const result1 = pipe(
fetchTransactionAmount,
Effect.map((amount) => amount * 2),
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(result1).then(console.log)
// Output: 190
// Using Effect.andThen
const result2 = pipe(
fetchTransactionAmount,
Effect.andThen((amount) => amount * 2),
Effect.andThen((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(result2).then(console.log)
// Output: 190

@since2.0.0

andThen
((
user: User
user
) =>
user: User
user
.
User.name: string
name
)
)

In the example above, a guard is used within the filterOrFail API to ensure that the user is of type User rather than User | null.

If you prefer, you can utilize a pre-made guard like Predicate.isNotNull for simplicity and consistency.

Similar to tapping for success values, Effect provides several operators for inspecting error values. These operators allow developers to observe failures or underlying issues without modifying the outcome.

Executes an effectful operation to inspect the failure of an effect without altering it.

Example (Inspecting Errors)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
// Simulate a task that fails with an error
const
const task: Effect.Effect<number, string, never>
task
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<number, string> =
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("NetworkError")
// Use tapError to log the error message when the task fails
const
const tapping: Effect.Effect<number, string, never>
tapping
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tapError: <number, string, never, void, never, never>(self: Effect.Effect<number, string, never>, f: (e: string) => Effect.Effect<void, never, never>) => Effect.Effect<number, string, never> (+1 overload)

The tapError function executes an effectful operation to inspect the failure of an effect without modifying it.

This function is useful when you want to perform some side effect (like logging or tracking) on the failure of an effect, but without changing the result of the effect itself. The error remains in the effect's error channel, while the operation you provide can inspect or act on it.

@example

import { Effect, Console } from "effect"
// Simulate a task that fails with an error
const task: Effect.Effect<number, string> = Effect.fail("NetworkError")
// Use tapError to log the error message when the task fails
const tapping = Effect.tapError(task, (error) =>
Console.log(`expected error: ${error}`)
)
Effect.runFork(tapping)
// Output:
// expected error: NetworkError

@since2.0.0

tapError
(
const task: Effect.Effect<number, string, never>
task
, (
error: string
error
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`expected error: ${
error: string
error
}`)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>

The foundational function for running effects, returning a "fiber" that can be observed or interrupted.

When to Use

runFork is used to run an effect in the background by creating a fiber. It is the base function for all other run functions. It starts a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const tapping: Effect.Effect<number, string, never>
tapping
)
/*
Output:
expected error: NetworkError
*/

This function allows you to inspect errors that match a specific tag, helping you handle different error types more precisely.

Example (Inspecting Tagged Errors)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
class
class NetworkError
NetworkError
{
readonly
NetworkError._tag: "NetworkError"
_tag
= "NetworkError"
constructor(readonly
NetworkError.statusCode: number
statusCode
: number) {}
}
class
class ValidationError
ValidationError
{
readonly
ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
constructor(readonly
ValidationError.field: string
field
: string) {}
}
// Create a task that fails with a NetworkError
const
const task: Effect.Effect<number, NetworkError | ValidationError, never>
task
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<number,
class NetworkError
NetworkError
|
class ValidationError
ValidationError
> =
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <NetworkError>(error: NetworkError) => Effect.Effect<never, NetworkError, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
(new
constructor NetworkError(statusCode: number): NetworkError
NetworkError
(504))
// Use tapErrorTag to inspect only NetworkError types and log the status code
const
const tapping: Effect.Effect<number, NetworkError | ValidationError, never>
tapping
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tapErrorTag: <number, NetworkError | ValidationError, never, "NetworkError", void, never, never>(self: Effect.Effect<number, NetworkError | ValidationError, never>, k: "NetworkError", f: (e: NetworkError) => Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

The tapErrorTag function allows you to inspect errors that match a specific tag, helping you handle different error types more precisely.

This function is useful when you want to target and act on specific error types within an effect. You can use it to handle errors more granularly based on their tags (e.g., inspecting only NetworkError or ValidationError), without modifying the error or the overall result of the effect.

@example

import { Effect, Console } from "effect"
class NetworkError {
readonly _tag = "NetworkError"
constructor(readonly statusCode: number) {}
}
class ValidationError {
readonly _tag = "ValidationError"
constructor(readonly field: string) {}
}
// Create a task that fails with a NetworkError
const task: Effect.Effect<number, NetworkError | ValidationError> =
Effect.fail(new NetworkError(504))
// Use tapErrorTag to inspect only NetworkError types and log the status code
const tapping = Effect.tapErrorTag(task, "NetworkError", (error) =>
Console.log(`expected error: ${error.statusCode}`)
)
Effect.runFork(tapping)
// Output:
// expected error: 504

@since2.0.0

tapErrorTag
(
const task: Effect.Effect<number, NetworkError | ValidationError, never>
task
, "NetworkError", (
error: NetworkError
error
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`expected error: ${
error: NetworkError
error
.
NetworkError.statusCode: number
statusCode
}`)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, NetworkError | ValidationError>(effect: Effect.Effect<number, NetworkError | ValidationError, never>, options?: RunForkOptions) => RuntimeFiber<...>

The foundational function for running effects, returning a "fiber" that can be observed or interrupted.

When to Use

runFork is used to run an effect in the background by creating a fiber. It is the base function for all other run functions. It starts a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const tapping: Effect.Effect<number, NetworkError | ValidationError, never>
tapping
)
/*
Output:
expected error: 504
*/

This function inspects the complete cause of an error, including failures and defects.

Example (Inspecting Error Causes)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
// Create a task that fails with a NetworkError
const
const task1: Effect.Effect<number, string, never>
task1
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<number, string> =
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("NetworkError")
const
const tapping1: Effect.Effect<number, string, never>
tapping1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tapErrorCause: <number, string, never, void, never, never>(self: Effect.Effect<number, string, never>, f: (cause: Cause<string>) => Effect.Effect<void, never, never>) => Effect.Effect<...> (+1 overload)

The tapErrorCause function allows you to inspect the complete cause of an error, including failures and defects.

This function is helpful when you need to log, monitor, or handle specific error causes in your effects. It gives you access to the full error cause, whether it’s a failure, defect, or other exceptional conditions, without altering the error or the overall result of the effect.

@example

import { Effect, Console } from "effect"
// Create a task that fails with a NetworkError
const task1: Effect.Effect<number, string> = Effect.fail("NetworkError")
const tapping1 = Effect.tapErrorCause(task1, (cause) =>
Console.log(`error cause: ${cause}`)
)
Effect.runFork(tapping1)
// Output:
// error cause: Error: NetworkError
// Simulate a severe failure in the system
const task2: Effect.Effect<number, string> = Effect.dieMessage(
"Something went wrong"
)
const tapping2 = Effect.tapErrorCause(task2, (cause) =>
Console.log(`error cause: ${cause}`)
)
Effect.runFork(tapping2)
// Output:
// error cause: RuntimeException: Something went wrong
// ... stack trace ...

@since2.0.0

tapErrorCause
(
const task1: Effect.Effect<number, string, never>
task1
, (
cause: Cause<string>
cause
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`error cause: ${
cause: Cause<string>
cause
}`)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>

The foundational function for running effects, returning a "fiber" that can be observed or interrupted.

When to Use

runFork is used to run an effect in the background by creating a fiber. It is the base function for all other run functions. It starts a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const tapping1: Effect.Effect<number, string, never>
tapping1
)
/*
Output:
error cause: Error: NetworkError
*/
// Simulate a severe failure in the system
const
const task2: Effect.Effect<number, string, never>
task2
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<number, string> =
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const dieMessage: (message: string) => Effect.Effect<never>

Creates an effect that terminates a fiber with a RuntimeException containing the specified message.

When to Use

Use dieMessage when you want to terminate a fiber due to an unrecoverable defect and include a clear explanation in the message.

Details

The dieMessage function is used to signal a defect, representing a critical and unexpected error in the code. When invoked, it produces an effect that terminates the fiber with a RuntimeException carrying the given message.

The resulting effect has an error channel of type never, indicating it does not handle or recover from the error.

@seedie for a variant that throws a specified error.

@seedieSync for a variant that throws a specified error, evaluated lazily.

@example

// Title: Terminating on Division by Zero with a Specified Message
import { Effect } from "effect"
const divide = (a: number, b: number) =>
b === 0
? Effect.dieMessage("Cannot divide by zero")
: Effect.succeed(a / b)
// ┌─── Effect<number, never, never>
// ▼
const program = divide(1, 0)
Effect.runPromise(program).catch(console.error)
// Output:
// (FiberFailure) RuntimeException: Cannot divide by zero
// ...stack trace...

@since2.0.0

dieMessage
(
"Something went wrong"
)
const
const tapping2: Effect.Effect<number, string, never>
tapping2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tapErrorCause: <number, string, never, void, never, never>(self: Effect.Effect<number, string, never>, f: (cause: Cause<string>) => Effect.Effect<void, never, never>) => Effect.Effect<...> (+1 overload)

The tapErrorCause function allows you to inspect the complete cause of an error, including failures and defects.

This function is helpful when you need to log, monitor, or handle specific error causes in your effects. It gives you access to the full error cause, whether it’s a failure, defect, or other exceptional conditions, without altering the error or the overall result of the effect.

@example

import { Effect, Console } from "effect"
// Create a task that fails with a NetworkError
const task1: Effect.Effect<number, string> = Effect.fail("NetworkError")
const tapping1 = Effect.tapErrorCause(task1, (cause) =>
Console.log(`error cause: ${cause}`)
)
Effect.runFork(tapping1)
// Output:
// error cause: Error: NetworkError
// Simulate a severe failure in the system
const task2: Effect.Effect<number, string> = Effect.dieMessage(
"Something went wrong"
)
const tapping2 = Effect.tapErrorCause(task2, (cause) =>
Console.log(`error cause: ${cause}`)
)
Effect.runFork(tapping2)
// Output:
// error cause: RuntimeException: Something went wrong
// ... stack trace ...

@since2.0.0

tapErrorCause
(
const task2: Effect.Effect<number, string, never>
task2
, (
cause: Cause<string>
cause
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`error cause: ${
cause: Cause<string>
cause
}`)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>

The foundational function for running effects, returning a "fiber" that can be observed or interrupted.

When to Use

runFork is used to run an effect in the background by creating a fiber. It is the base function for all other run functions. It starts a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const tapping2: Effect.Effect<number, string, never>
tapping2
)
/*
Output:
error cause: RuntimeException: Something went wrong
... stack trace ...
*/

Specifically inspects non-recoverable failures or defects in an effect (i.e., one or more Die causes).

Example (Inspecting Defects)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
// Simulate a task that fails with a recoverable error
const
const task1: Effect.Effect<number, string, never>
task1
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<number, string> =
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("NetworkError")
// tapDefect won't log anything because NetworkError is not a defect
const
const tapping1: Effect.Effect<number, string, never>
tapping1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tapDefect: <number, string, never, void, never, never>(self: Effect.Effect<number, string, never>, f: (cause: Cause<never>) => Effect.Effect<void, never, never>) => Effect.Effect<...> (+1 overload)

The tapDefect function specifically inspects non-recoverable failures or defects (i.e., one or more Die causes) in an effect.

This function is designed to catch severe errors in your program that represent critical issues, like system failures or unexpected errors (defects). It helps you log or handle these defects without altering the main result of the effect, allowing for efficient debugging or monitoring of severe errors.

@example

import { Effect, Console } from "effect"
// Simulate a task that fails with a recoverable error
const task1: Effect.Effect<number, string> = Effect.fail("NetworkError")
// tapDefect won't log anything because NetworkError is not a defect
const tapping1 = Effect.tapDefect(task1, (cause) =>
Console.log(`defect: ${cause}`)
)
Effect.runFork(tapping1)
// No Output
// Simulate a severe failure in the system
const task2: Effect.Effect<number, string> = Effect.dieMessage(
"Something went wrong"
)
// Log the defect using tapDefect
const tapping2 = Effect.tapDefect(task2, (cause) =>
Console.log(`defect: ${cause}`)
)
Effect.runFork(tapping2)
// Output:
// defect: RuntimeException: Something went wrong
// ... stack trace ...

@since2.0.0

tapDefect
(
const task1: Effect.Effect<number, string, never>
task1
, (
cause: Cause<never>
cause
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`defect: ${
cause: Cause<never>
cause
}`)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>

The foundational function for running effects, returning a "fiber" that can be observed or interrupted.

When to Use

runFork is used to run an effect in the background by creating a fiber. It is the base function for all other run functions. It starts a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const tapping1: Effect.Effect<number, string, never>
tapping1
)
/*
No Output
*/
// Simulate a severe failure in the system
const
const task2: Effect.Effect<number, string, never>
task2
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<number, string> =
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const dieMessage: (message: string) => Effect.Effect<never>

Creates an effect that terminates a fiber with a RuntimeException containing the specified message.

When to Use

Use dieMessage when you want to terminate a fiber due to an unrecoverable defect and include a clear explanation in the message.

Details

The dieMessage function is used to signal a defect, representing a critical and unexpected error in the code. When invoked, it produces an effect that terminates the fiber with a RuntimeException carrying the given message.

The resulting effect has an error channel of type never, indicating it does not handle or recover from the error.

@seedie for a variant that throws a specified error.

@seedieSync for a variant that throws a specified error, evaluated lazily.

@example

// Title: Terminating on Division by Zero with a Specified Message
import { Effect } from "effect"
const divide = (a: number, b: number) =>
b === 0
? Effect.dieMessage("Cannot divide by zero")
: Effect.succeed(a / b)
// ┌─── Effect<number, never, never>
// ▼
const program = divide(1, 0)
Effect.runPromise(program).catch(console.error)
// Output:
// (FiberFailure) RuntimeException: Cannot divide by zero
// ...stack trace...

@since2.0.0

dieMessage
(
"Something went wrong"
)
// Log the defect using tapDefect
const
const tapping2: Effect.Effect<number, string, never>
tapping2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tapDefect: <number, string, never, void, never, never>(self: Effect.Effect<number, string, never>, f: (cause: Cause<never>) => Effect.Effect<void, never, never>) => Effect.Effect<...> (+1 overload)

The tapDefect function specifically inspects non-recoverable failures or defects (i.e., one or more Die causes) in an effect.

This function is designed to catch severe errors in your program that represent critical issues, like system failures or unexpected errors (defects). It helps you log or handle these defects without altering the main result of the effect, allowing for efficient debugging or monitoring of severe errors.

@example

import { Effect, Console } from "effect"
// Simulate a task that fails with a recoverable error
const task1: Effect.Effect<number, string> = Effect.fail("NetworkError")
// tapDefect won't log anything because NetworkError is not a defect
const tapping1 = Effect.tapDefect(task1, (cause) =>
Console.log(`defect: ${cause}`)
)
Effect.runFork(tapping1)
// No Output
// Simulate a severe failure in the system
const task2: Effect.Effect<number, string> = Effect.dieMessage(
"Something went wrong"
)
// Log the defect using tapDefect
const tapping2 = Effect.tapDefect(task2, (cause) =>
Console.log(`defect: ${cause}`)
)
Effect.runFork(tapping2)
// Output:
// defect: RuntimeException: Something went wrong
// ... stack trace ...

@since2.0.0

tapDefect
(
const task2: Effect.Effect<number, string, never>
task2
, (
cause: Cause<never>
cause
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`defect: ${
cause: Cause<never>
cause
}`)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>

The foundational function for running effects, returning a "fiber" that can be observed or interrupted.

When to Use

runFork is used to run an effect in the background by creating a fiber. It is the base function for all other run functions. It starts a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const tapping2: Effect.Effect<number, string, never>
tapping2
)
/*
Output:
defect: RuntimeException: Something went wrong
... stack trace ...
*/

Inspects both success and failure outcomes of an effect, performing different actions based on the result.

Example (Inspecting Both Success and Failure)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Random
Random
,
import Console
Console
} from "effect"
// Simulate a task that might fail
const
const task: Effect.Effect<number, string, never>
task
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const filterOrFail: <number, never, never, string>(self: Effect.Effect<number, never, never>, predicate: Predicate<number>, orFailWith: (a: number) => string) => Effect.Effect<number, string, never> (+7 overloads)

Filter the specified effect with the provided function, failing with specified error if the predicate fails.

In addition to the filtering capabilities discussed earlier, you have the option to further refine and narrow down the type of the success channel by providing a user-defined type guard. Let's explore this concept through an example:

@example

import { Effect, pipe } from "effect"
// Define a user interface
interface User {
readonly name: string
}
// Simulate an asynchronous authentication function
declare const auth: () => Promise<User | null>
const program = pipe(
Effect.promise(() => auth()),
// Use filterOrFail with a custom type guard to ensure user is not null
Effect.filterOrFail(
(user): user is User => user !== null, // Type guard
() => new Error("Unauthorized")
),
// 'user' now has the type `User` (not `User | null`)
Effect.andThen((user) => user.name)
)

@since2.0.0

filterOrFail
(
import Random
Random
.
const nextRange: (min: number, max: number) => Effect.Effect<number>

Returns the next numeric value in the specified range from the pseudo-random number generator.

@since2.0.0

nextRange
(-1, 1),
(
n: number
n
) =>
n: number
n
>= 0,
() => "random number is negative"
)
// Use tapBoth to log both success and failure outcomes
const
const tapping: Effect.Effect<number, string, never>
tapping
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tapBoth: <number, string, never, void, never, never, void, never, never>(self: Effect.Effect<number, string, never>, options: {
readonly onFailure: (e: string) => Effect.Effect<void, never, never>;
readonly onSuccess: (a: number) => Effect.Effect<...>;
}) => Effect.Effect<...> (+1 overload)

The tapBoth function allows you to inspect both the success and failure outcomes of an effect, performing different actions based on the result.

This function is useful when you need to handle both successful results and failures separately, allowing for side effects such as logging, metrics collection, or conditional actions based on whether the effect succeeded or failed. It provides a way to react to the outcome of an effect without altering the result.

@example

import { Effect, Random, Console } from "effect"
// Simulate a task that might fail
const task = Effect.filterOrFail(
Random.nextRange(-1, 1),
(n) => n >= 0,
() => "random number is negative"
)
// Use tapBoth to log both success and failure outcomes
const tapping = Effect.tapBoth(task, {
onFailure: (error) => Console.log(`failure: ${error}`),
onSuccess: (randomNumber) =>
Console.log(`random number: ${randomNumber}`)
})
Effect.runFork(tapping)
// Example Output:
// failure: random number is negative

@since2.0.0

tapBoth
(
const task: Effect.Effect<number, string, never>
task
, {
onFailure: (e: string) => Effect.Effect<void, never, never>
onFailure
: (
error: string
error
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`failure: ${
error: string
error
}`),
onSuccess: (a: number) => Effect.Effect<void, never, never>
onSuccess
: (
randomNumber: number
randomNumber
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`random number: ${
randomNumber: number
randomNumber
}`)
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>

The foundational function for running effects, returning a "fiber" that can be observed or interrupted.

When to Use

runFork is used to run an effect in the background by creating a fiber. It is the base function for all other run functions. It starts a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const tapping: Effect.Effect<number, string, never>
tapping
)
/*
Example Output:
failure: random number is negative
*/

The Effect.either function transforms an Effect<A, E, R> into an effect that encapsulates both potential failure and success within an Either data type:

Effect<A, E, R> -> Effect<Either<A, E>, never, R>

This means if you have an effect with the following type:

Effect<string, HttpError, never>

and you call Effect.either on it, the type becomes:

Effect<Either<string, HttpError>, never, never>

The resulting effect cannot fail because the potential failure is now represented within the Either’s Left type. The error type of the returned Effect is specified as never, confirming that the effect is structured to not fail.

This function becomes especially useful when recovering from effects that may fail when using Effect.gen:

Example (Using Effect.either to Handle Errors)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Either

@since2.0.0

@since2.0.0

Either
,
import Console
Console
} from "effect"
// Simulate a task that fails
//
// ┌─── Either<number, string, never>
// ▼
const
const program: Effect.Effect<number, string, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh uh!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

as allows you to ignore the original value inside an effect and replace it with a new constant value.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(2))
// ┌─── Either<number, never, never>
// ▼
const
const recovered: Effect.Effect<number, never, never>
recovered
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, number>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, number, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
// ┌─── Either<number, string>
// ▼
const
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const either: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<Either.Either<number, string>, never, never>

Transforms an Effect into one that encapsulates both success and failure using the Either data type.

Details

either takes an effect that could potentially fail and converts it into an effect that always succeeds but with the result inside an Either. The Either can either be a Left (representing failure) or a Right (representing success). This allows you to handle both cases explicitly without causing the effect to fail.

The resulting effect cannot fail because failure is now represented inside the Either type.

@seeoption for a version that uses Option instead.

@seeexit for a version that uses Exit instead.

@example

import { Effect, Either, Random } from "effect"
class HttpError {
readonly _tag = "HttpError"
}
class ValidationError {
readonly _tag = "ValidationError"
}
// ┌─── Effect<string, HttpError | ValidationError, never>
// ▼
const program = Effect.gen(function* () {
const n1 = yield* Random.next
const n2 = yield* Random.next
if (n1 < 0.5) {
yield* Effect.fail(new HttpError())
}
if (n2 < 0.5) {
yield* Effect.fail(new ValidationError())
}
return "some result"
})
// ┌─── Effect<string, never, never>
// ▼
const recovered = Effect.gen(function* () {
// ┌─── Either<string, HttpError | ValidationError>
// ▼
const failureOrSuccess = yield* Effect.either(program)
return Either.match(failureOrSuccess, {
onLeft: (error) => `Recovering from ${error._tag}`,
onRight: (value) => value // Do nothing in case of success
})
})

@since2.0.0

either
(
const program: Effect.Effect<number, string, never>
program
)
if (
import Either

@since2.0.0

@since2.0.0

Either
.
const isLeft: <number, string>(self: Either.Either<number, string>) => self is Either.Left<string, number>

Determine if a Either is a Left.

@paramself - The Either to check.

@example

import { Either } from "effect"
assert.deepStrictEqual(Either.isLeft(Either.right(1)), false)
assert.deepStrictEqual(Either.isLeft(Either.left("a")), true)

@since2.0.0

isLeft
(
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
)) {
const
const error: string
error
=
const failureOrSuccess: Either.Left<string, number>
failureOrSuccess
.
Left<string, number>.left: string
left
yield*
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`failure: ${
const error: string
error
}`)
return 0
} else {
const
const value: number
value
=
const failureOrSuccess: Either.Right<string, number>
failureOrSuccess
.
Right<string, number>.right: number
right
yield*
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`success: ${
const value: number
value
}`)
return
const value: number
value
}
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <number, never>(effect: Effect.Effect<number, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<number>

Executes an effect and returns the result as a Promise.

When to Use

Use runPromise when you need to execute an effect and work with the result using Promise syntax, typically for compatibility with other promise-based code.

If the effect succeeds, the promise will resolve with the result. If the effect fails, the promise will reject with an error.

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@example

// Title: Running a Successful Effect as a Promise
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

@example

//Example: Handling a Failing Effect as a Rejected Promise import { Effect } from "effect"

Effect.runPromise(Effect.fail("my error")).catch(console.error) // Output: // (FiberFailure) Error: my error

@since2.0.0

runPromise
(
const recovered: Effect.Effect<number, never, never>
recovered
).
Promise<number>.then<void, never>(onfulfilled?: ((value: number) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
(
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
)
/*
Output:
failure: Oh uh!
0
*/

You can use the Effect.cause function to expose the cause of an effect, which is a more detailed representation of failures, including error messages and defects.

Example (Logging the Cause of Failure)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
// ┌─── Effect<number, string, never>
// ▼
const
const program: Effect.Effect<number, string, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh uh!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

as allows you to ignore the original value inside an effect and replace it with a new constant value.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(2))
// ┌─── Effect<void, never, never>
// ▼
const
const recovered: Effect.Effect<void, never, never>
recovered
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const cause: Cause<string>
cause
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const cause: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<Cause<string>, never, never>

The cause function allows you to expose the detailed cause of an effect, which includes a more precise representation of failures, such as error messages and defects.

This function is helpful when you need to inspect the cause of a failure in an effect, giving you more information than just the error message. It can be used to log, handle, or analyze failures in more detail, including distinguishing between different types of defects (e.g., runtime exceptions, interruptions, etc.).

@example

import { Effect, Console } from "effect"
// ┌─── Effect<number, string, never>
// ▼
const program = Effect.fail("Oh uh!").pipe(Effect.as(2))
// ┌─── Effect<void, never, never>
// ▼
const recovered = Effect.gen(function* () {
const cause = yield* Effect.cause(program)
yield* Console.log(cause)
})

@since2.0.0

cause
(
const program: Effect.Effect<number, string, never>
program
)
yield*
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(
const cause: Cause<string>
cause
)
})

The Effect.merge function allows you to combine the error channel with the success channel. This results in an effect that never fails; instead, both successes and errors are handled as values in the success channel.

Example (Combining Error and Success Channels)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// ┌─── Effect<number, string, never>
// ▼
const
const program: Effect.Effect<number, string, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh uh!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

as allows you to ignore the original value inside an effect and replace it with a new constant value.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(2))
// ┌─── Effect<number | string, never, never>
// ▼
const
const recovered: Effect.Effect<string | number, never, never>
recovered
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const merge: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<string | number, never, never>

The merge function combines both the error and success channels of an effect, creating a new effect that never fails.

This function transforms an effect that may fail into one that always returns a value, where both success and failure outcomes are handled as values in the success channel. This can be useful when you want to continue execution regardless of the error type and still capture both successful results and errors as part of the outcome.

@example

import { Effect } from "effect"
// ┌─── Effect<number, string, never>
// ▼
const program = Effect.fail("Oh uh!").pipe(Effect.as(2))
// ┌─── Effect<number | string, never, never>
// ▼
const recovered = Effect.merge(program)

@since2.0.0

merge
(
const program: Effect.Effect<number, string, never>
program
)

The Effect.flip function allows you to switch the error and success channels of an effect. This means that what was previously a success becomes the error, and vice versa.

Example (Swapping Error and Success Channels)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// ┌─── Effect<number, string, never>
// ▼
const
const program: Effect.Effect<number, string, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh uh!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

as allows you to ignore the original value inside an effect and replace it with a new constant value.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(2))
// ┌─── Effect<string, number, never>
// ▼
const
const flipped: Effect.Effect<string, number, never>
flipped
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const flip: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<string, number, never>

The flip function swaps the success and error channels of an effect, so that the success becomes the error, and the error becomes the success.

This function is useful when you need to reverse the flow of an effect, treating the previously successful values as errors and vice versa. This can be helpful in scenarios where you want to handle a success as a failure or treat an error as a valid result.

@example

import { Effect } from "effect"
// ┌─── Effect<number, string, never>
// ▼
const program = Effect.fail("Oh uh!").pipe(Effect.as(2))
// ┌─── Effect<string, number, never>
// ▼
const flipped = Effect.flip(program)

@since2.0.0

flip
(
const program: Effect.Effect<number, string, never>
program
)