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

1
import {
import Effect
Effect
} from "effect"
2
3
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("Oh no!").
(method) 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
Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

This function maps the success value of an `Effect` value to a specified constant value.

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

Returns an effect with its error channel mapped using the specified function.

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

We can observe that the type in the error channel of our program has changed from string to Error.

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

1
import {
import Effect
Effect
} from "effect"
2
3
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("Oh no!").
(method) 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
Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

This function maps the success value of an `Effect` value to a specified constant value.

as
(1))
4
5
const
const modified: Effect.Effect<boolean, Error, never>
modified
=
import Effect
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)

Returns an effect whose failure and success channels have been mapped by the specified `onFailure` and `onSuccess` functions.

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

After using mapBoth, we can observe that the type of our program has changed from Effect<number, string> to Effect<boolean, Error>.

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

1
import {
import Effect
Effect
,
import Random
Random
,
import Cause
Cause
} from "effect"
2
3
const
const task1: Effect.Effect<number, string, never>
task1
=
import Effect
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](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). Let's explore this concept through an example:

filterOrFail
(
4
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.

nextRange
(-1, 1),
5
(
(parameter) n: number
n
) =>
(parameter) n: number
n
>= 0,
6
() => "random number is negative"
7
)
8
9
const
const task2: Effect.Effect<number, never, never>
task2
=
import Effect
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.

filterOrDie
(
10
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.

nextRange
(-1, 1),
11
(
(parameter) n: number
n
) =>
(parameter) n: number
n
>= 0,
12
() => 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.

IllegalArgumentException
("random number is negative")
13
)
14
15
const
const task3: Effect.Effect<number, never, never>
task3
=
import Effect
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.

filterOrDieMessage
(
16
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.

nextRange
(-1, 1),
17
(
(parameter) n: number
n
) =>
(parameter) n: number
n
>= 0,
18
"random number is negative"
19
)
20
21
const
const task4: Effect.Effect<number, never, never>
task4
=
import Effect
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`.

filterOrElse
(
22
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.

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

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.

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 to the filterOr* APIs. This not only enhances type safety but also improves code clarity.

Example (Using a Type Guard)

1
import {
import Effect
Effect
,
(alias) function pipe<A>(a: A): A (+19 overloads) import pipe

Pipes the value of an expression into a pipeline of functions. This is useful in combination with data-last functions as a simulation of methods: ``` as.map(f).filter(g) -> pipe(as, map(f), filter(g)) ```

pipe
} from "effect"
2
3
// Define a user interface
4
interface
interface User
User
{
5
readonly
(property) User.name: string
name
: string
6
}
7
8
// Assume an asynchronous authentication function
9
declare const
const auth: () => Promise<User | null>
auth
: () =>
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<
interface User
User
| null>
10
11
const
const program: Effect.Effect<string, Error, never>
program
=
(alias) 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) import pipe

Pipes the value of an expression into a pipeline of functions. This is useful in combination with data-last functions as a simulation of methods: ``` as.map(f).filter(g) -> pipe(as, map(f), filter(g)) ```

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

Like `tryPromise` but produces a defect in case of errors. An optional `AbortSignal` can be provided to allow for interruption of the wrapped Promise api.

promise
(() =>
const auth: () => Promise<User | null>
auth
()),
13
import Effect
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](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). Let's explore this concept through an example:

filterOrFail
(
14
// Define a guard to narrow down the type
15
(
(parameter) user: User | null
user
):
(parameter) user: User | null
user
is
interface User
User
=>
(parameter) user: User | null
user
!== null,
16
() => new
var Error: ErrorConstructor new (message?: string) => Error
Error
("Unauthorized")
17
),
18
// The 'user' here has type `User`, not `User | null`
19
import Effect
Effect
.
const andThen: <User, string>(f: (a: User) => string) => <E, R>(self: Effect.Effect<User, E, R>) => Effect.Effect<string, E, R> (+3 overloads)

Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action. The `that` action can take various forms: - a value - a function returning a value - a promise - a function returning a promise - an effect - a function returning an effect

andThen
((
(parameter) user: User
user
) =>
(parameter) user: User
user
.
(property) User.name: string
name
)
20
)

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. This refined type information improves the reliability of your code and makes it more understandable.

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.

APIDescription
tapErrorExecutes an effectful operation to inspect the failure of an effect without altering it.
tapErrorTagSpecifically inspects a failure with a particular tag, allowing focused error handling.
tapErrorCauseInspects the underlying cause of an effect’s failure.
tapDefectSpecifically inspects non-recoverable failures or defects in an effect (i.e., one or more Die causes).
tapBothInspects both success and failure outcomes of an effect, performing different actions based on the result.

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

Example

1
import {
import Effect
Effect
,
import Console
Console
} from "effect"
2
3
// Create an effect that is designed to fail, simulating an occurrence
4
// of a network error
5
const
const task: Effect.Effect<number, string, never>
task
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<number, string> =
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("NetworkError")
6
7
// Log the error message if the task fails. This function only executes
8
// if there is an error, providing a method to handle or inspect errors
9
// without altering the outcome of the original effect.
10
const
const tapping: Effect.Effect<number, string, never>
tapping
=
import Effect
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)

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

tapError
(
const task: Effect.Effect<number, string, never>
task
, (
(parameter) error: string
error
) =>
11
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`expected error: ${
(parameter) error: string
error
}`)
12
)
13
14
import Effect
Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>
runFork
(
const tapping: Effect.Effect<number, string, never>
tapping
)
15
/*
16
Output:
17
expected error: NetworkError
18
*/

Specifically inspects a failure with a particular tag, allowing focused error handling.

Example

1
import {
import Effect
Effect
,
import Console
Console
} from "effect"
2
3
class
class NetworkError
NetworkError
{
4
readonly
(property) NetworkError._tag: "NetworkError"
_tag
= "NetworkError"
5
constructor(readonly
(property) NetworkError.statusCode: number
statusCode
: number) {}
6
}
7
8
class
class ValidationError
ValidationError
{
9
readonly
(property) ValidationError._tag: "ValidationError"
_tag
= "ValidationError"
10
constructor(readonly
(property) ValidationError.field: string
field
: string) {}
11
}
12
13
// Create an effect that is designed to fail, simulating an
14
// occurrence of a network error
15
const
const task: Effect.Effect<number, NetworkError | ValidationError, never>
task
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<number,
class NetworkError
NetworkError
|
class ValidationError
ValidationError
> =
16
import Effect
Effect
.
const fail: <NetworkError>(error: NetworkError) => Effect.Effect<never, NetworkError, never>
fail
(new
constructor NetworkError(statusCode: number): NetworkError
NetworkError
(504))
17
18
// Apply an error handling function only to errors tagged as
19
// "NetworkError", and log the corresponding status code of the error.
20
const
const tapping: Effect.Effect<number, NetworkError | ValidationError, never>
tapping
=
import Effect
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)

Specifically inspects a failure with a particular tag, allowing focused error handling.

tapErrorTag
(
const task: Effect.Effect<number, NetworkError | ValidationError, never>
task
, "NetworkError", (
(parameter) error: NetworkError
error
) =>
21
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`expected error: ${
(parameter) error: NetworkError
error
.
(property) NetworkError.statusCode: number
statusCode
}`)
22
)
23
24
import Effect
Effect
.
const runFork: <number, NetworkError | ValidationError>(effect: Effect.Effect<number, NetworkError | ValidationError, never>, options?: RunForkOptions) => RuntimeFiber<...>
runFork
(
const tapping: Effect.Effect<number, NetworkError | ValidationError, never>
tapping
)
25
/*
26
Output:
27
expected error: 504
28
*/

Inspects the underlying cause of an effect’s failure.

Example

1
import {
import Effect
Effect
,
import Console
Console
} from "effect"
2
3
// Create an effect that is designed to fail, simulating an occurrence of a
4
// network error
5
const
const task1: Effect.Effect<number, string, never>
task1
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<number, string> =
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("NetworkError")
6
7
// This will log the cause of any expected error or defect
8
const
const tapping1: Effect.Effect<number, string, never>
tapping1
=
import Effect
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)

Inspects the underlying cause of an effect's failure.

tapErrorCause
(
const task1: Effect.Effect<number, string, never>
task1
, (
(parameter) cause: Cause<string>
cause
) =>
9
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`error cause: ${
(parameter) cause: Cause<string>
cause
}`)
10
)
11
12
import Effect
Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>
runFork
(
const tapping1: Effect.Effect<number, string, never>
tapping1
)
13
/*
14
Output:
15
error cause: Error: NetworkError
16
*/
17
18
// Simulate a severe failure in the system by causing a defect with
19
// a specific message.
20
const
const task2: Effect.Effect<number, string, never>
task2
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

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

Returns an effect that dies with a `RuntimeException` having the specified text message. This method can be used for terminating a fiber because a defect has been detected in the code.

dieMessage
(
21
"Something went wrong"
22
)
23
24
// This will log the cause of any expected error or defect
25
const
const tapping2: Effect.Effect<number, string, never>
tapping2
=
import Effect
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)

Inspects the underlying cause of an effect's failure.

tapErrorCause
(
const task2: Effect.Effect<number, string, never>
task2
, (
(parameter) cause: Cause<string>
cause
) =>
26
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`error cause: ${
(parameter) cause: Cause<string>
cause
}`)
27
)
28
29
import Effect
Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>
runFork
(
const tapping2: Effect.Effect<number, string, never>
tapping2
)
30
/*
31
Output:
32
error cause: RuntimeException: Something went wrong
33
... stack trace ...
34
*/

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

Example

1
import {
import Effect
Effect
,
import Console
Console
} from "effect"
2
3
// Create an effect that is designed to fail, simulating an occurrence of a
4
// network error
5
const
const task1: Effect.Effect<number, string, never>
task1
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<number, string> =
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("NetworkError")
6
7
// this won't log anything because is not a defect
8
const
const tapping1: Effect.Effect<number, string, never>
tapping1
=
import Effect
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)

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

tapDefect
(
const task1: Effect.Effect<number, string, never>
task1
, (
(parameter) cause: Cause<never>
cause
) =>
9
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`defect: ${
(parameter) cause: Cause<never>
cause
}`)
10
)
11
12
import Effect
Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>
runFork
(
const tapping1: Effect.Effect<number, string, never>
tapping1
)
13
/*
14
No Output
15
*/
16
17
// Simulate a severe failure in the system by causing a defect with
18
// a specific message.
19
const
const task2: Effect.Effect<number, string, never>
task2
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

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

Returns an effect that dies with a `RuntimeException` having the specified text message. This method can be used for terminating a fiber because a defect has been detected in the code.

dieMessage
(
20
"Something went wrong"
21
)
22
23
// This will only log defects, not errors
24
const
const tapping2: Effect.Effect<number, string, never>
tapping2
=
import Effect
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)

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

tapDefect
(
const task2: Effect.Effect<number, string, never>
task2
, (
(parameter) cause: Cause<never>
cause
) =>
25
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`defect: ${
(parameter) cause: Cause<never>
cause
}`)
26
)
27
28
import Effect
Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>
runFork
(
const tapping2: Effect.Effect<number, string, never>
tapping2
)
29
/*
30
Output:
31
defect: RuntimeException: Something went wrong
32
... stack trace ...
33
*/

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

Example

1
import {
import Effect
Effect
,
import Random
Random
,
import Console
Console
} from "effect"
2
3
// Simulate an effect that might fail
4
const
const task: Effect.Effect<number, string, never>
task
=
import Effect
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](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). Let's explore this concept through an example:

filterOrFail
(
5
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.

nextRange
(-1, 1),
6
(
(parameter) n: number
n
) =>
(parameter) n: number
n
>= 0,
7
() => "random number is negative"
8
)
9
10
// Define an effect that logs both success and failure outcomes
11
// of the task
12
const
const tapping: Effect.Effect<number, string, never>
tapping
=
import Effect
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)

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

tapBoth
(
const task: Effect.Effect<number, string, never>
task
, {
13
(property) onFailure: (e: string) => Effect.Effect<void, never, never>
onFailure
: (
(parameter) error: string
error
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`failure: ${
(parameter) error: string
error
}`),
14
(property) onSuccess: (a: number) => Effect.Effect<void, never, never>
onSuccess
: (
(parameter) randomNumber: number
randomNumber
) =>
15
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`random number: ${
(parameter) randomNumber: number
randomNumber
}`)
16
})
17
18
import Effect
Effect
.
const runFork: <number, string>(effect: Effect.Effect<number, string, never>, options?: RunForkOptions) => RuntimeFiber<number, string>
runFork
(
const tapping: Effect.Effect<number, string, never>
tapping
)
19
/*
20
Example Output:
21
failure: random number is negative
22
*/

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>

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:

1
import {
import Effect
Effect
,
import Either
Either
,
import Console
Console
} from "effect"
2
3
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("Oh uh!").
(method) 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
Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

This function maps the success value of an `Effect` value to a specified constant value.

as
(2))
4
5
const
const program: Effect.Effect<number, never, never>
program
=
import Effect
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)
gen
(function* () {
6
const
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
= yield*
import Effect
Effect
.
const either: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<Either.Either<number, string>, never, never>

Returns an effect whose failure and success have been lifted into an `Either`. The resulting effect cannot fail, because the failure case has been exposed as part of the `Either` success case. This method is useful for recovering from effects that may fail. The error parameter of the returned `Effect` is `never`, since it is guaranteed the effect does not model failure.

either
(
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
)
7
if (
import Either
Either
.
const isLeft: <number, string>(self: Either.Either<number, string>) => self is Either.Left<string, number>

Determine if a `Either` is a `Left`.

isLeft
(
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
)) {
8
const
const error: string
error
=
const failureOrSuccess: Either.Left<string, number>
failureOrSuccess
.
(property) Left<string, number>.left: string
left
9
yield*
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`failure: ${
const error: string
error
}`)
10
return 0
11
} else {
12
const
const value: number
value
=
const failureOrSuccess: Either.Right<string, number>
failureOrSuccess
.
(property) Right<string, number>.right: number
right
13
yield*
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(`success: ${
const value: number
value
}`)
14
return
const value: number
value
15
}
16
})

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

1
import {
import Effect
Effect
,
import Console
Console
} from "effect"
2
3
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("Oh uh!").
(method) 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
Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

This function maps the success value of an `Effect` value to a specified constant value.

as
(2))
4
5
const
const program: Effect.Effect<void, never, never>
program
=
import Effect
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)
gen
(function* () {
6
const
const cause: Cause<string>
cause
= yield*
import Effect
Effect
.
const cause: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<Cause<string>, never, never>

Returns an effect that succeeds with the cause of failure of this effect, or `Cause.empty` if the effect did succeed.

cause
(
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
)
7
yield*
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(
const cause: Cause<string>
cause
)
8
})

Using the Effect.merge function, you can merge the error channel into the success channel, creating an effect that always succeeds with the merged value.

Example

1
import {
import Effect
Effect
} from "effect"
2
3
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("Oh uh!").
(method) 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
Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

This function maps the success value of an `Effect` value to a specified constant value.

as
(2))
4
5
const
const merged: Effect.Effect<string | number, never, never>
merged
=
import Effect
Effect
.
const merge: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<string | number, never, never>

Returns a new effect where the error channel has been merged into the success channel to their common combined type.

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

Using the Effect.flip function, you can flip the error and success channels of an effect, effectively swapping their roles.

Example

1
import {
import Effect
Effect
} from "effect"
2
3
const
const simulatedTask: Effect.Effect<number, string, never>
simulatedTask
=
import Effect
Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>
fail
("Oh uh!").
(method) 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
Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

This function maps the success value of an `Effect` value to a specified constant value.

as
(2))
4
5
const
const flipped: Effect.Effect<string, number, never>
flipped
=
import Effect
Effect
.
const flip: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<string, number, never>

Returns an effect that swaps the error/success cases. This allows you to use all methods on the error channel, possibly before flipping back.

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