Skip to content

Ref

When we write programs, it is common to need to keep track of some form of state during the execution of the program. State refers to any data that can change as the program runs. For example, in a counter application, the count value changes as the user increments or decrements it. Similarly, in a banking application, the account balance changes as deposits and withdrawals are made. State management is crucial to building interactive and dynamic applications.

In traditional imperative programming, one common way to store state is using variables. However, this approach can introduce bugs, especially when the state is shared between multiple components or functions. As the program becomes more complex, managing shared state can become challenging.

To overcome these issues, Effect introduces a powerful data type called Ref, which represents a mutable reference. With Ref, we can share state between different parts of our program without relying on mutable variables directly. Instead, Ref provides a controlled way to handle mutable state and safely update it in a concurrent environment.

Effect’s Ref data type enables communication between different fibers in your program. This capability is crucial in concurrent programming, where multiple tasks may need to access and update shared state simultaneously.

In this guide, we will explore how to use the Ref data type to manage state in your programs effectively. We will cover simple examples like counting, as well as more complex scenarios where state is shared between different parts of the program. Additionally, we will show how to use Ref in a concurrent environment, allowing multiple tasks to interact with shared state safely.

Let’s dive in and see how we can leverage Ref for effective state management in your Effect programs.

Here is a simple example using Ref to create a counter:

Example (Basic Counter with Ref)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Ref
Ref
} from "effect"
class
class Counter
Counter
{
Counter.inc: Effect.Effect<void, never, never>
inc
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<void>
Counter.dec: Effect.Effect<void, never, never>
dec
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<void>
Counter.get: Effect.Effect<number, never, never>
get
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<number>
constructor(private
Counter.value: Ref.Ref<number>
value
:
import Ref
Ref
.
interface Ref<in out A>

@since2.0.0

@since2.0.0

Ref
<number>) {
this.
Counter.inc: Effect.Effect<void, never, never>
inc
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(this.
Counter.value: Ref.Ref<number>
value
, (
n: number
n
) =>
n: number
n
+ 1)
this.
Counter.dec: Effect.Effect<void, never, never>
dec
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(this.
Counter.value: Ref.Ref<number>
value
, (
n: number
n
) =>
n: number
n
- 1)
this.
Counter.get: Effect.Effect<number, never, never>
get
=
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>

@since2.0.0

get
(this.
Counter.value: Ref.Ref<number>
value
)
}
}
const
const make: Effect.Effect<Counter, never, never>
make
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const andThen: <Ref.Ref<number>, never, never, Counter>(self: Effect.Effect<Ref.Ref<number>, never, never>, f: (a: Ref.Ref<number>) => Counter) => Effect.Effect<Counter, never, never> (+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
(
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>

@since2.0.0

make
(0), (
value: Ref.Ref<number>
value
) => new
constructor Counter(value: Ref.Ref<number>): Counter
Counter
(
value: Ref.Ref<number>
value
))

Example (Using the Counter)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Ref
Ref
} from "effect"
13 collapsed lines
class
class Counter
Counter
{
Counter.inc: Effect.Effect<void, never, never>
inc
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<void>
Counter.dec: Effect.Effect<void, never, never>
dec
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<void>
Counter.get: Effect.Effect<number, never, never>
get
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<number>
constructor(private
Counter.value: Ref.Ref<number>
value
:
import Ref
Ref
.
interface Ref<in out A>

@since2.0.0

@since2.0.0

Ref
<number>) {
this.
Counter.inc: Effect.Effect<void, never, never>
inc
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(this.
Counter.value: Ref.Ref<number>
value
, (
n: number
n
) =>
n: number
n
+ 1)
this.
Counter.dec: Effect.Effect<void, never, never>
dec
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(this.
Counter.value: Ref.Ref<number>
value
, (
n: number
n
) =>
n: number
n
- 1)
this.
Counter.get: Effect.Effect<number, never, never>
get
=
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>

@since2.0.0

get
(this.
Counter.value: Ref.Ref<number>
value
)
}
}
const
const make: Effect.Effect<Counter, never, never>
make
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const andThen: <Ref.Ref<number>, never, never, Counter>(self: Effect.Effect<Ref.Ref<number>, never, never>, f: (a: Ref.Ref<number>) => Counter) => Effect.Effect<Counter, never, never> (+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
(
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>

@since2.0.0

make
(0), (
value: Ref.Ref<number>
value
) => new
constructor Counter(value: Ref.Ref<number>): Counter
Counter
(
value: Ref.Ref<number>
value
))
const
const program: Effect.Effect<void, never, never>
program
=
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

Effect.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 counter: Counter
counter
= yield*
const make: Effect.Effect<Counter, never, never>
make
yield*
const counter: Counter
counter
.
Counter.inc: Effect.Effect<void, never, never>
inc
yield*
const counter: Counter
counter
.
Counter.inc: Effect.Effect<void, never, never>
inc
yield*
const counter: Counter
counter
.
Counter.dec: Effect.Effect<void, never, never>
dec
yield*
const counter: Counter
counter
.
Counter.inc: Effect.Effect<void, never, never>
inc
const
const value: number
value
= yield*
const counter: Counter
counter
.
Counter.get: Effect.Effect<number, never, never>
get
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
.
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
(`This counter has a value of ${
const value: number
value
}.`)
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

@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 program: Effect.Effect<void, never, never>
program
)
/*
Output:
This counter has a value of 2.
*/

We can also use Ref in concurrent scenarios, where multiple tasks might be updating shared state at the same time.

Example (Concurrent Updates to Shared Counter)

For this example, let’s update the counter concurrently:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Ref
Ref
} from "effect"
13 collapsed lines
class
class Counter
Counter
{
Counter.inc: Effect.Effect<void, never, never>
inc
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<void>
Counter.dec: Effect.Effect<void, never, never>
dec
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<void>
Counter.get: Effect.Effect<number, never, never>
get
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<number>
constructor(private
Counter.value: Ref.Ref<number>
value
:
import Ref
Ref
.
interface Ref<in out A>

@since2.0.0

@since2.0.0

Ref
<number>) {
this.
Counter.inc: Effect.Effect<void, never, never>
inc
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(this.
Counter.value: Ref.Ref<number>
value
, (
n: number
n
) =>
n: number
n
+ 1)
this.
Counter.dec: Effect.Effect<void, never, never>
dec
=
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(this.
Counter.value: Ref.Ref<number>
value
, (
n: number
n
) =>
n: number
n
- 1)
this.
Counter.get: Effect.Effect<number, never, never>
get
=
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>

@since2.0.0

get
(this.
Counter.value: Ref.Ref<number>
value
)
}
}
const
const make: Effect.Effect<Counter, never, never>
make
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const andThen: <Ref.Ref<number>, never, never, Counter>(self: Effect.Effect<Ref.Ref<number>, never, never>, f: (a: Ref.Ref<number>) => Counter) => Effect.Effect<Counter, never, never> (+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
(
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>

@since2.0.0

make
(0), (
value: Ref.Ref<number>
value
) => new
constructor Counter(value: Ref.Ref<number>): Counter
Counter
(
value: Ref.Ref<number>
value
))
const
const program: Effect.Effect<void, never, never>
program
=
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

Effect.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 counter: Counter
counter
= yield*
const make: Effect.Effect<Counter, never, never>
make
// Helper to log the counter's value before running an effect
const
const logCounter: <R, E, A>(label: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
logCounter
= <
function (type parameter) R in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
R
,
function (type parameter) E in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
E
,
function (type parameter) A in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
A
>(
label: string
label
: string,
effect: Effect.Effect<A, E, R>
effect
:
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<
function (type parameter) A in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
A
,
function (type parameter) E in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
E
,
function (type parameter) R in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
R
>
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.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 value: number
value
= yield*
const counter: Counter
counter
.
Counter.get: Effect.Effect<number, never, never>
get
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
(`${
label: string
label
} get: ${
const value: number
value
}`)
return yield*
effect: Effect.Effect<A, E, R>
effect
})
yield*
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 1",
const counter: Counter
counter
.
Counter.inc: Effect.Effect<void, never, never>
inc
).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<[void, void], never, never>, Effect.Effect<[[void, void], void], never, never>, Effect.Effect<[[[void, void], void], void], never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const zip: <void, never, never>(that: Effect.Effect<void, never, never>, options?: {
readonly concurrent?: boolean | undefined;
readonly batching?: boolean | "inherit" | undefined;
readonly concurrentFinalizers?: boolean | undefined;
} | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Combines two effects into a single effect, producing a tuple of their results.

Details

This function combines two effects, self and that, into one. It executes the first effect (self) and then the second effect (that), collecting their results into a tuple. Both effects must succeed for the resulting effect to succeed. If either effect fails, the entire operation fails.

By default, the effects are executed sequentially. If the concurrent option is set to true, the effects will run concurrently, potentially improving performance for independent operations.

@seezipWith for a version that combines the results with a custom function.

@seevalidate for a version that accumulates errors.

@example

// Title: Combining Two Effects Sequentially
import { Effect } from "effect"
const task1 = Effect.succeed(1).pipe(
Effect.delay("200 millis"),
Effect.tap(Effect.log("task1 done"))
)
const task2 = Effect.succeed("hello").pipe(
Effect.delay("100 millis"),
Effect.tap(Effect.log("task2 done"))
)
// Combine the two effects together
//
// ┌─── Effect<[number, string], never, never>
// ▼
const program = Effect.zip(task1, task2)
// Effect.runPromise(program).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="task1 done"
// timestamp=... level=INFO fiber=#0 message="task2 done"
// [ 1, 'hello' ]

@example

// Title: Combining Two Effects Concurrently import { Effect } from "effect"

const task1 = Effect.succeed(1).pipe( Effect.delay("200 millis"), Effect.tap(Effect.log("task1 done")) ) const task2 = Effect.succeed("hello").pipe( Effect.delay("100 millis"), Effect.tap(Effect.log("task2 done")) )

// Run both effects concurrently using the concurrent option const program = Effect.zip(task1, task2, { concurrent: true })

// Effect.runPromise(program).then(console.log) // Output: // timestamp=... level=INFO fiber=#0 message="task2 done" // timestamp=... level=INFO fiber=#0 message="task1 done" // [ 1, 'hello' ]

@since2.0.0

zip
(
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 2",
const counter: Counter
counter
.
Counter.inc: Effect.Effect<void, never, never>
inc
), {
concurrent?: boolean | undefined
concurrent
: true }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const zip: <void, never, never>(that: Effect.Effect<void, never, never>, options?: {
readonly concurrent?: boolean | undefined;
readonly batching?: boolean | "inherit" | undefined;
readonly concurrentFinalizers?: boolean | undefined;
} | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Combines two effects into a single effect, producing a tuple of their results.

Details

This function combines two effects, self and that, into one. It executes the first effect (self) and then the second effect (that), collecting their results into a tuple. Both effects must succeed for the resulting effect to succeed. If either effect fails, the entire operation fails.

By default, the effects are executed sequentially. If the concurrent option is set to true, the effects will run concurrently, potentially improving performance for independent operations.

@seezipWith for a version that combines the results with a custom function.

@seevalidate for a version that accumulates errors.

@example

// Title: Combining Two Effects Sequentially
import { Effect } from "effect"
const task1 = Effect.succeed(1).pipe(
Effect.delay("200 millis"),
Effect.tap(Effect.log("task1 done"))
)
const task2 = Effect.succeed("hello").pipe(
Effect.delay("100 millis"),
Effect.tap(Effect.log("task2 done"))
)
// Combine the two effects together
//
// ┌─── Effect<[number, string], never, never>
// ▼
const program = Effect.zip(task1, task2)
// Effect.runPromise(program).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="task1 done"
// timestamp=... level=INFO fiber=#0 message="task2 done"
// [ 1, 'hello' ]

@example

// Title: Combining Two Effects Concurrently import { Effect } from "effect"

const task1 = Effect.succeed(1).pipe( Effect.delay("200 millis"), Effect.tap(Effect.log("task1 done")) ) const task2 = Effect.succeed("hello").pipe( Effect.delay("100 millis"), Effect.tap(Effect.log("task2 done")) )

// Run both effects concurrently using the concurrent option const program = Effect.zip(task1, task2, { concurrent: true })

// Effect.runPromise(program).then(console.log) // Output: // timestamp=... level=INFO fiber=#0 message="task2 done" // timestamp=... level=INFO fiber=#0 message="task1 done" // [ 1, 'hello' ]

@since2.0.0

zip
(
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 3",
const counter: Counter
counter
.
Counter.dec: Effect.Effect<void, never, never>
dec
), {
concurrent?: boolean | undefined
concurrent
: true }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const zip: <void, never, never>(that: Effect.Effect<void, never, never>, options?: {
readonly concurrent?: boolean | undefined;
readonly batching?: boolean | "inherit" | undefined;
readonly concurrentFinalizers?: boolean | undefined;
} | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Combines two effects into a single effect, producing a tuple of their results.

Details

This function combines two effects, self and that, into one. It executes the first effect (self) and then the second effect (that), collecting their results into a tuple. Both effects must succeed for the resulting effect to succeed. If either effect fails, the entire operation fails.

By default, the effects are executed sequentially. If the concurrent option is set to true, the effects will run concurrently, potentially improving performance for independent operations.

@seezipWith for a version that combines the results with a custom function.

@seevalidate for a version that accumulates errors.

@example

// Title: Combining Two Effects Sequentially
import { Effect } from "effect"
const task1 = Effect.succeed(1).pipe(
Effect.delay("200 millis"),
Effect.tap(Effect.log("task1 done"))
)
const task2 = Effect.succeed("hello").pipe(
Effect.delay("100 millis"),
Effect.tap(Effect.log("task2 done"))
)
// Combine the two effects together
//
// ┌─── Effect<[number, string], never, never>
// ▼
const program = Effect.zip(task1, task2)
// Effect.runPromise(program).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="task1 done"
// timestamp=... level=INFO fiber=#0 message="task2 done"
// [ 1, 'hello' ]

@example

// Title: Combining Two Effects Concurrently import { Effect } from "effect"

const task1 = Effect.succeed(1).pipe( Effect.delay("200 millis"), Effect.tap(Effect.log("task1 done")) ) const task2 = Effect.succeed("hello").pipe( Effect.delay("100 millis"), Effect.tap(Effect.log("task2 done")) )

// Run both effects concurrently using the concurrent option const program = Effect.zip(task1, task2, { concurrent: true })

// Effect.runPromise(program).then(console.log) // Output: // timestamp=... level=INFO fiber=#0 message="task2 done" // timestamp=... level=INFO fiber=#0 message="task1 done" // [ 1, 'hello' ]

@since2.0.0

zip
(
const logCounter: <never, never, void>(label: string, effect: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>
logCounter
("task 4",
const counter: Counter
counter
.
Counter.inc: Effect.Effect<void, never, never>
inc
), {
concurrent?: boolean | undefined
concurrent
: true })
)
const
const value: number
value
= yield*
const counter: Counter
counter
.
Counter.get: Effect.Effect<number, never, never>
get
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
(`This counter has a value of ${
const value: number
value
}.`)
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

@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 program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... fiber=#3 message="task 4 get: 0"
timestamp=... fiber=#6 message="task 3 get: 1"
timestamp=... fiber=#8 message="task 1 get: 0"
timestamp=... fiber=#9 message="task 2 get: 1"
timestamp=... fiber=#0 message="This counter has a value of 2."
*/

You can pass a Ref as a service to share state across different parts of your program.

Example (Using Ref as a Service)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Ref
Ref
} from "effect"
// Create a Tag for our state
class
class MyState
MyState
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"MyState">(id: "MyState") => <Self, Shape>() => Context.TagClass<Self, "MyState", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("MyState")<
class MyState
MyState
,
import Ref
Ref
.
interface Ref<in out A>

@since2.0.0

@since2.0.0

Ref
<number>
>() {}
// Subprogram 1: Increment the state value twice
const
const subprogram1: Effect.Effect<void, never, MyState>
subprogram1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.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 state: Ref.Ref<number>
state
= yield*
class MyState
MyState
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(
const state: Ref.Ref<number>
state
, (
n: number
n
) =>
n: number
n
+ 1)
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(
const state: Ref.Ref<number>
state
, (
n: number
n
) =>
n: number
n
+ 1)
})
// Subprogram 2: Decrement the state value and then increment it
const
const subprogram2: Effect.Effect<void, never, MyState>
subprogram2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.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 state: Ref.Ref<number>
state
= yield*
class MyState
MyState
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(
const state: Ref.Ref<number>
state
, (
n: number
n
) =>
n: number
n
- 1)
yield*
import Ref
Ref
.
const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(
const state: Ref.Ref<number>
state
, (
n: number
n
) =>
n: number
n
+ 1)
})
// Subprogram 3: Read and log the current value of the state
const
const subprogram3: Effect.Effect<void, never, MyState>
subprogram3
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.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 state: Ref.Ref<number>
state
= yield*
class MyState
MyState
const
const value: number
value
= yield*
import Ref
Ref
.
const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>

@since2.0.0

get
(
const state: Ref.Ref<number>
state
)
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
.
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
(`MyState has a value of ${
const value: number
value
}.`)
})
// Compose subprograms 1, 2, and 3 to create the main program
const
const program: Effect.Effect<void, never, MyState>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, MyState>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, MyState>>, 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

Effect.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* () {
yield*
const subprogram1: Effect.Effect<void, never, MyState>
subprogram1
yield*
const subprogram2: Effect.Effect<void, never, MyState>
subprogram2
yield*
const subprogram3: Effect.Effect<void, never, MyState>
subprogram3
})
// Create a Ref instance with an initial value of 0
const
const initialState: Effect.Effect<Ref.Ref<number>, never, never>
initialState
=
import Ref
Ref
.
const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>

@since2.0.0

make
(0)
// Provide the Ref as a service
const
const runnable: Effect.Effect<void, never, never>
runnable
=
const program: Effect.Effect<void, never, MyState>
program
.
Pipeable.pipe<Effect.Effect<void, never, MyState>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, MyState>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provideServiceEffect: <MyState, Ref.Ref<number>, never, never>(tag: Context.Tag<MyState, Ref.Ref<number>>, effect: Effect.Effect<Ref.Ref<number>, never, never>) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

Dynamically provides an implementation for a service using an effect.

Details

This function allows you to provide an implementation for a service dynamically by using another effect. The provided effect is executed to produce the service implementation, which is then made available to the consuming effect. This is particularly useful when the service implementation itself requires asynchronous or resource-intensive initialization.

For example, you can use this function to lazily initialize a database connection or fetch configuration values from an external source before making the service available to your effect.

@since2.0.0

provideServiceEffect
(
class MyState
MyState
,
const initialState: Effect.Effect<Ref.Ref<number>, never, never>
initialState
)
)
// Run the program and observe the output
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

@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 runnable: Effect.Effect<void, never, never>
runnable
)
/*
Output:
MyState has a value of 2.
*/

Note that we use Effect.provideServiceEffect instead of Effect.provideService to provide an actual implementation of the MyState service because all the operations on the Ref data type are effectful, including the creation Ref.make(0).

You can use Ref to manage shared state between multiple fibers in a concurrent environment.

Example (Managing Shared State Across Fibers)

Let’s look at an example where we continuously read names from user input until the user enters "q" to exit.

First, let’s introduce a readLine utility to read user input (ensure you have @types/node installed):

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
import * as
module "node:readline"
NodeReadLine
from "node:readline"
// Utility to read user input
const
const readLine: (message: string) => Effect.Effect<string>
readLine
= (
message: string
message
: string):
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<string> =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

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.

When to Use

Use this function when you are sure the operation will not reject.

@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
(
() =>
new
var Promise: PromiseConstructor
new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>

Creates a new Promise.

@paramexecutor A callback used to initialize the promise. This callback is passed two arguments: a resolve callback used to resolve the promise with a value or the result of another promise, and a reject callback used to reject the promise with a provided reason or error.

Promise
((
resolve: (value: string | PromiseLike<string>) => void
resolve
) => {
const
const rl: NodeReadLine.Interface
rl
=
module "node:readline"
NodeReadLine
.
function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)

The readline.createInterface() method creates a new readline.Interface instance.

import readline from 'node:readline';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

Once the readline.Interface instance is created, the most common case is to listen for the 'line' event:

rl.on('line', (line) => {
console.log(`Received: ${line}`);
});

If terminal is true for this instance then the output stream will get the best compatibility if it defines an output.columns property and emits a 'resize' event on the output if or when the columns ever change (process.stdout does this automatically when it is a TTY).

When creating a readline.Interface using stdin as input, the program will not terminate until it receives an EOF character. To exit without waiting for user input, call process.stdin.unref().

@sincev0.1.98

createInterface
({
ReadLineOptions.input: NodeJS.ReadableStream

The Readable stream to listen to

input
:
var process: NodeJS.Process
process
.
NodeJS.Process.stdin: NodeJS.ReadStream & {
fd: 0;
}

The process.stdin property returns a stream connected tostdin (fd 0). It is a net.Socket (which is a Duplex stream) unless fd 0 refers to a file, in which case it is a Readable stream.

For details of how to read from stdin see readable.read().

As a Duplex stream, process.stdin can also be used in "old" mode that is compatible with scripts written for Node.js prior to v0.10. For more information see Stream compatibility.

In "old" streams mode the stdin stream is paused by default, so one must call process.stdin.resume() to read from it. Note also that calling process.stdin.resume() itself would switch stream to "old" mode.

stdin
,
ReadLineOptions.output?: NodeJS.WritableStream | undefined

The Writable stream to write readline data to.

output
:
var process: NodeJS.Process
process
.
NodeJS.Process.stdout: NodeJS.WriteStream & {
fd: 1;
}

The process.stdout property returns a stream connected tostdout (fd 1). It is a net.Socket (which is a Duplex stream) unless fd 1 refers to a file, in which case it is a Writable stream.

For example, to copy process.stdin to process.stdout:

import { stdin, stdout } from 'node:process';
stdin.pipe(stdout);

process.stdout differs from other Node.js streams in important ways. See note on process I/O for more information.

stdout
})
const rl: NodeReadLine.Interface
rl
.
Interface.question(query: string, callback: (answer: string) => void): void (+1 overload)

The rl.question() method displays the query by writing it to the output, waits for user input to be provided on input, then invokes the callback function passing the provided input as the first argument.

When called, rl.question() will resume the input stream if it has been paused.

If the Interface was created with output set to null or undefined the query is not written.

The callback function passed to rl.question() does not follow the typical pattern of accepting an Error object or null as the first argument. The callback is called with the provided answer as the only argument.

An error will be thrown if calling rl.question() after rl.close().

Example usage:

rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});

Using an AbortController to cancel a question.

const ac = new AbortController();
const signal = ac.signal;
rl.question('What is your favorite food? ', { signal }, (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
setTimeout(() => ac.abort(), 10000);

@sincev0.3.3

@paramquery A statement or query to write to output, prepended to the prompt.

@paramcallback A callback function that is invoked with the user's input in response to the query.

question
(
message: string
message
, (
answer: string
answer
) => {
const rl: NodeReadLine.Interface
rl
.
Interface.close(): void

The rl.close() method closes the Interface instance and relinquishes control over the input and output streams. When called, the 'close' event will be emitted.

Calling rl.close() does not immediately stop other events (including 'line') from being emitted by the Interface instance.

@sincev0.1.98

close
()
resolve: (value: string | PromiseLike<string>) => void
resolve
(
answer: string
answer
)
})
})
)

Next, we implement the main program to collect names:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Chunk
Chunk
,
import Ref
Ref
} from "effect"
import * as
module "node:readline"
NodeReadLine
from "node:readline"
// Utility to read user input
14 collapsed lines
const
const readLine: (message: string) => Effect.Effect<string>
readLine
= (
message: string
message
: string):
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<string> =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

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.

When to Use

Use this function when you are sure the operation will not reject.

@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
(
() =>
new
var Promise: PromiseConstructor
new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>

Creates a new Promise.

@paramexecutor A callback used to initialize the promise. This callback is passed two arguments: a resolve callback used to resolve the promise with a value or the result of another promise, and a reject callback used to reject the promise with a provided reason or error.

Promise
((
resolve: (value: string | PromiseLike<string>) => void
resolve
) => {
const
const rl: NodeReadLine.Interface
rl
=
module "node:readline"
NodeReadLine
.
function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)

The readline.createInterface() method creates a new readline.Interface instance.

import readline from 'node:readline';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

Once the readline.Interface instance is created, the most common case is to listen for the 'line' event:

rl.on('line', (line) => {
console.log(`Received: ${line}`);
});

If terminal is true for this instance then the output stream will get the best compatibility if it defines an output.columns property and emits a 'resize' event on the output if or when the columns ever change (process.stdout does this automatically when it is a TTY).

When creating a readline.Interface using stdin as input, the program will not terminate until it receives an EOF character. To exit without waiting for user input, call process.stdin.unref().

@sincev0.1.98

createInterface
({
ReadLineOptions.input: NodeJS.ReadableStream

The Readable stream to listen to

input
:
var process: NodeJS.Process
process
.
NodeJS.Process.stdin: NodeJS.ReadStream & {
fd: 0;
}

The process.stdin property returns a stream connected tostdin (fd 0). It is a net.Socket (which is a Duplex stream) unless fd 0 refers to a file, in which case it is a Readable stream.

For details of how to read from stdin see readable.read().

As a Duplex stream, process.stdin can also be used in "old" mode that is compatible with scripts written for Node.js prior to v0.10. For more information see Stream compatibility.

In "old" streams mode the stdin stream is paused by default, so one must call process.stdin.resume() to read from it. Note also that calling process.stdin.resume() itself would switch stream to "old" mode.

stdin
,
ReadLineOptions.output?: NodeJS.WritableStream | undefined

The Writable stream to write readline data to.

output
:
var process: NodeJS.Process
process
.
NodeJS.Process.stdout: NodeJS.WriteStream & {
fd: 1;
}

The process.stdout property returns a stream connected tostdout (fd 1). It is a net.Socket (which is a Duplex stream) unless fd 1 refers to a file, in which case it is a Writable stream.

For example, to copy process.stdin to process.stdout:

import { stdin, stdout } from 'node:process';
stdin.pipe(stdout);

process.stdout differs from other Node.js streams in important ways. See note on process I/O for more information.

stdout
})
const rl: NodeReadLine.Interface
rl
.
Interface.question(query: string, callback: (answer: string) => void): void (+1 overload)

The rl.question() method displays the query by writing it to the output, waits for user input to be provided on input, then invokes the callback function passing the provided input as the first argument.

When called, rl.question() will resume the input stream if it has been paused.

If the Interface was created with output set to null or undefined the query is not written.

The callback function passed to rl.question() does not follow the typical pattern of accepting an Error object or null as the first argument. The callback is called with the provided answer as the only argument.

An error will be thrown if calling rl.question() after rl.close().

Example usage:

rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});

Using an AbortController to cancel a question.

const ac = new AbortController();
const signal = ac.signal;
rl.question('What is your favorite food? ', { signal }, (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
setTimeout(() => ac.abort(), 10000);

@sincev0.3.3

@paramquery A statement or query to write to output, prepended to the prompt.

@paramcallback A callback function that is invoked with the user's input in response to the query.

question
(
message: string
message
, (
answer: string
answer
) => {
const rl: NodeReadLine.Interface
rl
.
Interface.close(): void

The rl.close() method closes the Interface instance and relinquishes control over the input and output streams. When called, the 'close' event will be emitted.

Calling rl.close() does not immediately stop other events (including 'line') from being emitted by the Interface instance.

@sincev0.1.98

close
()
resolve: (value: string | PromiseLike<string>) => void
resolve
(
answer: string
answer
)
})
})
)
const
const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.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 ref: Ref.Ref<Chunk.Chunk<string>>
ref
= yield*
import Ref
Ref
.
const make: <Chunk.Chunk<string>>(value: Chunk.Chunk<string>) => Effect.Effect<Ref.Ref<Chunk.Chunk<string>>, never, never>

@since2.0.0

make
(
import Chunk
Chunk
.
const empty: <string>() => Chunk.Chunk<string>

@since2.0.0

empty
<string>())
while (true) {
const
const name: string
name
= yield*
const readLine: (message: string) => Effect.Effect<string>
readLine
("Please enter a name or `q` to exit: ")
if (
const name: string
name
=== "q") {
break
}
yield*
import Ref
Ref
.
const update: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>, f: (a: Chunk.Chunk<string>) => Chunk.Chunk<string>) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
, (
state: Chunk.Chunk<string>
state
) =>
import Chunk
Chunk
.
const append: <string, string>(self: Chunk.Chunk<string>, a: string) => Chunk.NonEmptyChunk<string> (+1 overload)

Appends the specified element to the end of the Chunk.

@since2.0.0

append
(
state: Chunk.Chunk<string>
state
,
const name: string
name
))
}
return yield*
import Ref
Ref
.
const get: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>) => Effect.Effect<Chunk.Chunk<string>, never, never>

@since2.0.0

get
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
)
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

@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 getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
).
Promise<Chunk<string>>.then<void, never>(onfulfilled?: ((value: Chunk.Chunk<string>) => 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
.
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:
Please enter a name or `q` to exit: Alice
Please enter a name or `q` to exit: Bob
Please enter a name or `q` to exit: q
{
_id: "Chunk",
values: [ "Alice", "Bob" ]
}
*/

Now that we have learned how to use the Ref data type, we can use it to manage the state concurrently.

For example, assume while we are reading from the console, we have another fiber that is trying to update the state from a different source.

Here, one fiber reads names from user input, while another fiber concurrently adds preset names at regular intervals:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Chunk
Chunk
,
import Ref
Ref
,
import Fiber
Fiber
} from "effect"
import * as
module "node:readline"
NodeReadLine
from "node:readline"
// Utility to read user input
14 collapsed lines
const
const readLine: (message: string) => Effect.Effect<string>
readLine
= (
message: string
message
: string):
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 describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<string> =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

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.

When to Use

Use this function when you are sure the operation will not reject.

@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
(
() =>
new
var Promise: PromiseConstructor
new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>

Creates a new Promise.

@paramexecutor A callback used to initialize the promise. This callback is passed two arguments: a resolve callback used to resolve the promise with a value or the result of another promise, and a reject callback used to reject the promise with a provided reason or error.

Promise
((
resolve: (value: string | PromiseLike<string>) => void
resolve
) => {
const
const rl: NodeReadLine.Interface
rl
=
module "node:readline"
NodeReadLine
.
function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)

The readline.createInterface() method creates a new readline.Interface instance.

import readline from 'node:readline';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

Once the readline.Interface instance is created, the most common case is to listen for the 'line' event:

rl.on('line', (line) => {
console.log(`Received: ${line}`);
});

If terminal is true for this instance then the output stream will get the best compatibility if it defines an output.columns property and emits a 'resize' event on the output if or when the columns ever change (process.stdout does this automatically when it is a TTY).

When creating a readline.Interface using stdin as input, the program will not terminate until it receives an EOF character. To exit without waiting for user input, call process.stdin.unref().

@sincev0.1.98

createInterface
({
ReadLineOptions.input: NodeJS.ReadableStream

The Readable stream to listen to

input
:
var process: NodeJS.Process
process
.
NodeJS.Process.stdin: NodeJS.ReadStream & {
fd: 0;
}

The process.stdin property returns a stream connected tostdin (fd 0). It is a net.Socket (which is a Duplex stream) unless fd 0 refers to a file, in which case it is a Readable stream.

For details of how to read from stdin see readable.read().

As a Duplex stream, process.stdin can also be used in "old" mode that is compatible with scripts written for Node.js prior to v0.10. For more information see Stream compatibility.

In "old" streams mode the stdin stream is paused by default, so one must call process.stdin.resume() to read from it. Note also that calling process.stdin.resume() itself would switch stream to "old" mode.

stdin
,
ReadLineOptions.output?: NodeJS.WritableStream | undefined

The Writable stream to write readline data to.

output
:
var process: NodeJS.Process
process
.
NodeJS.Process.stdout: NodeJS.WriteStream & {
fd: 1;
}

The process.stdout property returns a stream connected tostdout (fd 1). It is a net.Socket (which is a Duplex stream) unless fd 1 refers to a file, in which case it is a Writable stream.

For example, to copy process.stdin to process.stdout:

import { stdin, stdout } from 'node:process';
stdin.pipe(stdout);

process.stdout differs from other Node.js streams in important ways. See note on process I/O for more information.

stdout
})
const rl: NodeReadLine.Interface
rl
.
Interface.question(query: string, callback: (answer: string) => void): void (+1 overload)

The rl.question() method displays the query by writing it to the output, waits for user input to be provided on input, then invokes the callback function passing the provided input as the first argument.

When called, rl.question() will resume the input stream if it has been paused.

If the Interface was created with output set to null or undefined the query is not written.

The callback function passed to rl.question() does not follow the typical pattern of accepting an Error object or null as the first argument. The callback is called with the provided answer as the only argument.

An error will be thrown if calling rl.question() after rl.close().

Example usage:

rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});

Using an AbortController to cancel a question.

const ac = new AbortController();
const signal = ac.signal;
rl.question('What is your favorite food? ', { signal }, (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
setTimeout(() => ac.abort(), 10000);

@sincev0.3.3

@paramquery A statement or query to write to output, prepended to the prompt.

@paramcallback A callback function that is invoked with the user's input in response to the query.

question
(
message: string
message
, (
answer: string
answer
) => {
const rl: NodeReadLine.Interface
rl
.
Interface.close(): void

The rl.close() method closes the Interface instance and relinquishes control over the input and output streams. When called, the 'close' event will be emitted.

Calling rl.close() does not immediately stop other events (including 'line') from being emitted by the Interface instance.

@sincev0.1.98

close
()
resolve: (value: string | PromiseLike<string>) => void
resolve
(
answer: string
answer
)
})
})
)
const
const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.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 ref: Ref.Ref<Chunk.Chunk<string>>
ref
= yield*
import Ref
Ref
.
const make: <Chunk.Chunk<string>>(value: Chunk.Chunk<string>) => Effect.Effect<Ref.Ref<Chunk.Chunk<string>>, never, never>

@since2.0.0

make
(
import Chunk
Chunk
.
const empty: <string>() => Chunk.Chunk<string>

@since2.0.0

empty
<string>())
// Fiber 1: Reading names from user input
const
const fiber1: Fiber.RuntimeFiber<void, never>
fiber1
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fork: <void, never, never>(self: Effect.Effect<void, never, never>) => Effect.Effect<Fiber.RuntimeFiber<void, never>, never, never>

Creates a new fiber to run an effect concurrently.

Details

This function takes an effect and forks it into a separate fiber, allowing it to run concurrently without blocking the original effect. The new fiber starts execution immediately after being created, and the fiber object is returned immediately without waiting for the effect to begin. This is useful when you want to run tasks concurrently while continuing other tasks in the parent fiber.

The forked fiber is attached to the parent fiber's scope. This means that when the parent fiber terminates, the child fiber will also be terminated automatically. This feature, known as "auto supervision," ensures that no fibers are left running unintentionally. If you prefer not to have this auto supervision behavior, you can use

forkDaemon

or

forkIn

.

When to Use

Use this function when you need to run an effect concurrently without blocking the current execution flow. For example, you might use it to launch background tasks or concurrent computations. However, working with fibers can be complex, so before using this function directly, you might want to explore higher-level functions like

raceWith

,

zip

, or others that can manage concurrency for you.

@seeforkWithErrorHandler for a version that allows you to handle errors.

@example

import { Effect } from "effect"
const fib = (n: number): Effect.Effect<number> =>
n < 2
? Effect.succeed(n)
: Effect.zipWith(fib(n - 1), fib(n - 2), (a, b) => a + b)
// ┌─── Effect<RuntimeFiber<number, never>, never, never>
// ▼
const fib10Fiber = Effect.fork(fib(10))

@since2.0.0

fork
(
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

Effect.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* () {
while (true) {
const
const name: string
name
= yield*
const readLine: (message: string) => Effect.Effect<string>
readLine
(
"Please enter a name or `q` to exit: "
)
if (
const name: string
name
=== "q") {
break
}
yield*
import Ref
Ref
.
const update: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>, f: (a: Chunk.Chunk<string>) => Chunk.Chunk<string>) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
, (
state: Chunk.Chunk<string>
state
) =>
import Chunk
Chunk
.
const append: <string, string>(self: Chunk.Chunk<string>, a: string) => Chunk.NonEmptyChunk<string> (+1 overload)

Appends the specified element to the end of the Chunk.

@since2.0.0

append
(
state: Chunk.Chunk<string>
state
,
const name: string
name
))
}
})
)
// Fiber 2: Updating the state with predefined names
const
const fiber2: Fiber.RuntimeFiber<void, never>
fiber2
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fork: <void, never, never>(self: Effect.Effect<void, never, never>) => Effect.Effect<Fiber.RuntimeFiber<void, never>, never, never>

Creates a new fiber to run an effect concurrently.

Details

This function takes an effect and forks it into a separate fiber, allowing it to run concurrently without blocking the original effect. The new fiber starts execution immediately after being created, and the fiber object is returned immediately without waiting for the effect to begin. This is useful when you want to run tasks concurrently while continuing other tasks in the parent fiber.

The forked fiber is attached to the parent fiber's scope. This means that when the parent fiber terminates, the child fiber will also be terminated automatically. This feature, known as "auto supervision," ensures that no fibers are left running unintentionally. If you prefer not to have this auto supervision behavior, you can use

forkDaemon

or

forkIn

.

When to Use

Use this function when you need to run an effect concurrently without blocking the current execution flow. For example, you might use it to launch background tasks or concurrent computations. However, working with fibers can be complex, so before using this function directly, you might want to explore higher-level functions like

raceWith

,

zip

, or others that can manage concurrency for you.

@seeforkWithErrorHandler for a version that allows you to handle errors.

@example

import { Effect } from "effect"
const fib = (n: number): Effect.Effect<number> =>
n < 2
? Effect.succeed(n)
: Effect.zipWith(fib(n - 1), fib(n - 2), (a, b) => a + b)
// ┌─── Effect<RuntimeFiber<number, never>, never, never>
// ▼
const fib10Fiber = Effect.fork(fib(10))

@since2.0.0

fork
(
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

Effect.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* () {
for (const
const name: string
name
of ["John", "Jane", "Joe", "Tom"]) {
yield*
import Ref
Ref
.
const update: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>, f: (a: Chunk.Chunk<string>) => Chunk.Chunk<string>) => Effect.Effect<void> (+1 overload)

@since2.0.0

update
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
, (
state: Chunk.Chunk<string>
state
) =>
import Chunk
Chunk
.
const append: <string, string>(self: Chunk.Chunk<string>, a: string) => Chunk.NonEmptyChunk<string> (+1 overload)

Appends the specified element to the end of the Chunk.

@since2.0.0

append
(
state: Chunk.Chunk<string>
state
,
const name: string
name
))
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("1 second")
}
})
)
yield*
import Fiber
Fiber
.
const join: <void, never>(self: Fiber.Fiber<void, never>) => Effect.Effect<void, never, never>

Joins the fiber, which suspends the joining fiber until the result of the fiber has been determined. Attempting to join a fiber that has erred will result in a catchable error. Joining an interrupted fiber will result in an "inner interruption" of this fiber, unlike interruption triggered by another fiber, "inner interruption" can be caught and recovered.

@since2.0.0

join
(
const fiber1: Fiber.RuntimeFiber<void, never>
fiber1
)
yield*
import Fiber
Fiber
.
const join: <void, never>(self: Fiber.Fiber<void, never>) => Effect.Effect<void, never, never>

Joins the fiber, which suspends the joining fiber until the result of the fiber has been determined. Attempting to join a fiber that has erred will result in a catchable error. Joining an interrupted fiber will result in an "inner interruption" of this fiber, unlike interruption triggered by another fiber, "inner interruption" can be caught and recovered.

@since2.0.0

join
(
const fiber2: Fiber.RuntimeFiber<void, never>
fiber2
)
return yield*
import Ref
Ref
.
const get: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>) => Effect.Effect<Chunk.Chunk<string>, never, never>

@since2.0.0

get
(
const ref: Ref.Ref<Chunk.Chunk<string>>
ref
)
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

@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 getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames
).
Promise<Chunk<string>>.then<void, never>(onfulfilled?: ((value: Chunk.Chunk<string>) => 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
.
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:
Please enter a name or `q` to exit: Alice
Please enter a name or `q` to exit: Bob
Please enter a name or `q` to exit: q
{
_id: "Chunk",
// Note: the following result may vary
// depending on the speed of user input
values: [ 'John', 'Jane', 'Joe', 'Tom', 'Alice', 'Bob' ]
}
*/