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
)
1import { import Effect
Effect, import Ref
Ref } from "effect"2
3class class Counter
Counter {4 (property) Counter.inc: Effect.Effect<void, never, never>
inc: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>5 (property) Counter.dec: Effect.Effect<void, never, never>
dec: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>6 (property) Counter.get: Effect.Effect<number, never, never>
get: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number>7
8 constructor(private (property) Counter.value: Ref.Ref<number>
value: import Ref
Ref.interface Ref<in out A>
namespace Ref
Ref<number>) {9 this.(property) 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)
update(this.(property) Counter.value: Ref.Ref<number>
value, ((parameter) n: number
n) => (parameter) n: number
n + 1)10 this.(property) 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)
update(this.(property) Counter.value: Ref.Ref<number>
value, ((parameter) n: number
n) => (parameter) n: number
n - 1)11 this.(property) Counter.get: Effect.Effect<number, never, never>
get = import Ref
Ref.const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get(this.(property) Counter.value: Ref.Ref<number>
value)12 }13}14
15const const make: Effect.Effect<Counter, never, never>
make = import Effect
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)
Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action.
The `that` action can take various forms:
- a value
- a function returning a value
- a promise
- a function returning a promise
- an effect
- a function returning an effect
andThen(import Ref
Ref.const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>
make(0), ((parameter) value: Ref.Ref<number>
value) => new constructor Counter(value: Ref.Ref<number>): Counter
Counter((parameter) value: Ref.Ref<number>
value))
Example (Using the Counter)
1import { import Effect
Effect, import Ref
Ref } from "effect"2
13 collapsed lines
3class class Counter
Counter {4 (property) Counter.inc: Effect.Effect<void, never, never>
inc: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>5 (property) Counter.dec: Effect.Effect<void, never, never>
dec: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>6 (property) Counter.get: Effect.Effect<number, never, never>
get: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number>7
8 constructor(private (property) Counter.value: Ref.Ref<number>
value: import Ref
Ref.interface Ref<in out A>
namespace Ref
Ref<number>) {9 this.(property) 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)
update(this.(property) Counter.value: Ref.Ref<number>
value, ((parameter) n: number
n) => (parameter) n: number
n + 1)10 this.(property) 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)
update(this.(property) Counter.value: Ref.Ref<number>
value, ((parameter) n: number
n) => (parameter) n: number
n - 1)11 this.(property) Counter.get: Effect.Effect<number, never, never>
get = import Ref
Ref.const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get(this.(property) Counter.value: Ref.Ref<number>
value)12 }13}14
15const const make: Effect.Effect<Counter, never, never>
make = import Effect
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)
Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action.
The `that` action can take various forms:
- a value
- a function returning a value
- a promise
- a function returning a promise
- an effect
- a function returning an effect
andThen(import Ref
Ref.const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>
make(0), ((parameter) value: Ref.Ref<number>
value) => new constructor Counter(value: Ref.Ref<number>): Counter
Counter((parameter) value: Ref.Ref<number>
value))16
17const const program: Effect.Effect<void, never, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {18 const const counter: Counter
counter = yield* const make: Effect.Effect<Counter, never, never>
make19 yield* const counter: Counter
counter.(property) Counter.inc: Effect.Effect<void, never, never>
inc20 yield* const counter: Counter
counter.(property) Counter.inc: Effect.Effect<void, never, never>
inc21 yield* const counter: Counter
counter.(property) Counter.dec: Effect.Effect<void, never, never>
dec22 yield* const counter: Counter
counter.(property) Counter.inc: Effect.Effect<void, never, never>
inc23 const const value: number
value = yield* const counter: Counter
counter.(property) Counter.get: Effect.Effect<number, never, never>
get24 namespace console
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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
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:
```js
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
```
console.(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`This counter has a value of ${const value: number
value}.`)25})26
27import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const program: Effect.Effect<void, never, never>
program)28/*29Output:30This counter has a value of 2.31*/
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:
1import { import Effect
Effect, import Ref
Ref } from "effect"2
13 collapsed lines
3class class Counter
Counter {4 (property) Counter.inc: Effect.Effect<void, never, never>
inc: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>5 (property) Counter.dec: Effect.Effect<void, never, never>
dec: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void>6 (property) Counter.get: Effect.Effect<number, never, never>
get: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number>7
8 constructor(private (property) Counter.value: Ref.Ref<number>
value: import Ref
Ref.interface Ref<in out A>
namespace Ref
Ref<number>) {9 this.(property) 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)
update(this.(property) Counter.value: Ref.Ref<number>
value, ((parameter) n: number
n) => (parameter) n: number
n + 1)10 this.(property) 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)
update(this.(property) Counter.value: Ref.Ref<number>
value, ((parameter) n: number
n) => (parameter) n: number
n - 1)11 this.(property) Counter.get: Effect.Effect<number, never, never>
get = import Ref
Ref.const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get(this.(property) Counter.value: Ref.Ref<number>
value)12 }13}14
15const const make: Effect.Effect<Counter, never, never>
make = import Effect
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)
Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action.
The `that` action can take various forms:
- a value
- a function returning a value
- a promise
- a function returning a promise
- an effect
- a function returning an effect
andThen(import Ref
Ref.const make: <number>(value: number) => Effect.Effect<Ref.Ref<number>, never, never>
make(0), ((parameter) value: Ref.Ref<number>
value) => new constructor Counter(value: Ref.Ref<number>): Counter
Counter((parameter) value: Ref.Ref<number>
value))16
17const const program: Effect.Effect<void, never, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {18 const const counter: Counter
counter = yield* const make: Effect.Effect<Counter, never, never>
make19
20 // Helper to log the counter's value before running an effect21 const const logCounter: <R, E, A>(label: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
logCounter = <(type parameter) R in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
R, (type parameter) E in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
E, (type parameter) A in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
A>(22 (parameter) label: string
label: string,23 (parameter) effect: Effect.Effect<A, E, R>
effect: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<(type parameter) A in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
A, (type parameter) E in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
E, (type parameter) R in <R, E, A>(label: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
R>24 ) =>25 import Effect
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)
gen(function* () {26 const const value: number
value = yield* const counter: Counter
counter.(property) Counter.get: Effect.Effect<number, never, never>
get27 yield* import Effect
Effect.const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>
Logs one or more messages or error causes at the current log level, which is INFO by default.
This function allows logging multiple items at once and can include detailed error information using `Cause` instances.
To adjust the log level, use the `Logger.withMinimumLogLevel` function.
log(`${(parameter) label: string
label} get: ${const value: number
value}`)28 return yield* (parameter) effect: Effect.Effect<A, E, R>
effect29 })30
31 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.(property) Counter.inc: Effect.Effect<void, never, never>
inc).(method) 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(32 import Effect
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)
The `Effect.zip` function allows you to combine two effects into a single
effect. This combined effect yields a tuple containing the results of both
input effects once they succeed.
Note that `Effect.zip` processes effects sequentially: it first completes the
effect on the left and then the effect on the right.
If you want to run the effects concurrently, you can use the `concurrent` option.
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.(property) Counter.inc: Effect.Effect<void, never, never>
inc), { (property) concurrent?: boolean | undefined
concurrent: true }),33 import Effect
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)
The `Effect.zip` function allows you to combine two effects into a single
effect. This combined effect yields a tuple containing the results of both
input effects once they succeed.
Note that `Effect.zip` processes effects sequentially: it first completes the
effect on the left and then the effect on the right.
If you want to run the effects concurrently, you can use the `concurrent` option.
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.(property) Counter.dec: Effect.Effect<void, never, never>
dec), { (property) concurrent?: boolean | undefined
concurrent: true }),34 import Effect
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)
The `Effect.zip` function allows you to combine two effects into a single
effect. This combined effect yields a tuple containing the results of both
input effects once they succeed.
Note that `Effect.zip` processes effects sequentially: it first completes the
effect on the left and then the effect on the right.
If you want to run the effects concurrently, you can use the `concurrent` option.
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.(property) Counter.inc: Effect.Effect<void, never, never>
inc), { (property) concurrent?: boolean | undefined
concurrent: true })35 )36 const const value: number
value = yield* const counter: Counter
counter.(property) Counter.get: Effect.Effect<number, never, never>
get37 yield* import Effect
Effect.const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>
Logs one or more messages or error causes at the current log level, which is INFO by default.
This function allows logging multiple items at once and can include detailed error information using `Cause` instances.
To adjust the log level, use the `Logger.withMinimumLogLevel` function.
log(`This counter has a value of ${const value: number
value}.`)38})39
40import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const program: Effect.Effect<void, never, never>
program)41/*42Output:43timestamp=... fiber=#3 message="task 4 get: 0"44timestamp=... fiber=#6 message="task 3 get: 1"45timestamp=... fiber=#8 message="task 1 get: 0"46timestamp=... fiber=#9 message="task 2 get: 1"47timestamp=... fiber=#0 message="This counter has a value of 2."48*/
You can pass a Ref
as a service to share state across different parts of your program.
Example (Using Ref
as a Service)
1import { import Effect
Effect, import Context
Context, import Ref
Ref } from "effect"2
3// Create a Tag for our state4class class MyState
MyState extends import Context
Context.const Tag: <"MyState">(id: "MyState") => <Self, Shape>() => Context.TagClass<Self, "MyState", Shape>
namespace Tag
Tag("MyState")<5 class MyState
MyState,6 import Ref
Ref.interface Ref<in out A>
namespace Ref
Ref<number>7>() {}8
9// Subprogram 1: Increment the state value twice10const const subprogram1: Effect.Effect<void, never, MyState>
subprogram1 = import Effect
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)
gen(function* () {11 const const state: Ref.Ref<number>
state = yield* class MyState
MyState12 yield* import Ref
Ref.const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update(const state: Ref.Ref<number>
state, ((parameter) n: number
n) => (parameter) n: number
n + 1)13 yield* import Ref
Ref.const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update(const state: Ref.Ref<number>
state, ((parameter) n: number
n) => (parameter) n: number
n + 1)14})15
16// Subprogram 2: Decrement the state value and then increment it17const const subprogram2: Effect.Effect<void, never, MyState>
subprogram2 = import Effect
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)
gen(function* () {18 const const state: Ref.Ref<number>
state = yield* class MyState
MyState19 yield* import Ref
Ref.const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update(const state: Ref.Ref<number>
state, ((parameter) n: number
n) => (parameter) n: number
n - 1)20 yield* import Ref
Ref.const update: <number>(self: Ref.Ref<number>, f: (a: number) => number) => Effect.Effect<void> (+1 overload)
update(const state: Ref.Ref<number>
state, ((parameter) n: number
n) => (parameter) n: number
n + 1)21})22
23// Subprogram 3: Read and log the current value of the state24const const subprogram3: Effect.Effect<void, never, MyState>
subprogram3 = import Effect
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)
gen(function* () {25 const const state: Ref.Ref<number>
state = yield* class MyState
MyState26 const const value: number
value = yield* import Ref
Ref.const get: <number>(self: Ref.Ref<number>) => Effect.Effect<number, never, never>
get(const state: Ref.Ref<number>
state)27 namespace console
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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
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:
```js
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
```
console.(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`MyState has a value of ${const value: number
value}.`)28})29
30// Compose subprograms 1, 2, and 3 to create the main program31const const program: Effect.Effect<void, never, MyState>
program = import Effect
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)
gen(function* () {32 yield* const subprogram1: Effect.Effect<void, never, MyState>
subprogram133 yield* const subprogram2: Effect.Effect<void, never, MyState>
subprogram234 yield* const subprogram3: Effect.Effect<void, never, MyState>
subprogram335})36
37// Create a Ref instance with an initial value of 038const 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>
make(0)39
40// Provide the Ref as a service41const const runnable: Effect.Effect<void, never, never>
runnable = const program: Effect.Effect<void, never, MyState>
program.(method) 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(42 import Effect
Effect.const provideServiceEffect: <typeof MyState, never, never>(tag: typeof MyState, effect: Effect.Effect<Ref.Ref<number>, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+1 overload)
Provides the effect with the single service it requires. If the effect
requires more than one service use `provide` instead.
provideServiceEffect(class MyState
MyState, const initialState: Effect.Effect<Ref.Ref<number>, never, never>
initialState)43)44
45// Run the program and observe the output46import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const runnable: Effect.Effect<void, never, never>
runnable)47/*48Output:49MyState has a value of 2.50*/
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):
1import { import Effect
Effect } from "effect"2import * as (alias) module "node:readline"
import NodeReadLine
NodeReadLine from "node:readline"3
4// Utility to read user input5const const readLine: (message: string) => Effect.Effect<string>
readLine = ((parameter) message: string
message: string): import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<string> =>6 import Effect
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.
The provided function (`thunk`) returns a `Promise` that should never reject.
If the `Promise` does reject, the rejection is treated as a defect.
An optional `AbortSignal` can be provided to allow for interruption of the
wrapped `Promise` API.
promise(7 () =>8 new var Promise: PromiseConstructor
new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>
Creates a new Promise.
Promise(((parameter) resolve: (value: string | PromiseLike<string>) => void
resolve) => {9 const const rl: NodeReadLine.Interface
rl = (alias) module "node:readline"
import NodeReadLine
NodeReadLine.function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)
The `readline.createInterface()` method creates a new `readline.Interface` instance.
```js
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:
```js
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](https://en.wikipedia.org/wiki/End-of-file#EOF_character). To exit without
waiting for user input, call `process.stdin.unref()`.
createInterface({10 (property) ReadLineOptions.input: NodeJS.ReadableStream
input: var process: NodeJS.Process
process.(property) NodeJS.Process.stdin: NodeJS.ReadStream & {
fd: 0;
}
The `process.stdin` property returns a stream connected to`stdin` (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,11 (property) ReadLineOptions.output?: NodeJS.WritableStream | undefined
output: var process: NodeJS.Process
process.(property) NodeJS.Process.stdout: NodeJS.WriteStream & {
fd: 1;
}
The `process.stdout` property returns a stream connected to`stdout` (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`:
```js
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.
stdout12 })13 const rl: NodeReadLine.Interface
rl.(method) 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:
```js
rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
```
Using an `AbortController` to cancel a question.
```js
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);
```
question((parameter) message: string
message, ((parameter) answer: string
answer) => {14 const rl: NodeReadLine.Interface
rl.(method) 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.
close()15 (parameter) resolve: (value: string | PromiseLike<string>) => void
resolve((parameter) answer: string
answer)16 })17 })18 )
Next, we implement the main program to collect names:
1import { import Effect
Effect, import Chunk
Chunk, import Ref
Ref } from "effect"2import * as (alias) module "node:readline"
import NodeReadLine
NodeReadLine from "node:readline"3
4// Utility to read user input14 collapsed lines
5const const readLine: (message: string) => Effect.Effect<string>
readLine = ((parameter) message: string
message: string): import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<string> =>6 import Effect
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.
The provided function (`thunk`) returns a `Promise` that should never reject.
If the `Promise` does reject, the rejection is treated as a defect.
An optional `AbortSignal` can be provided to allow for interruption of the
wrapped `Promise` API.
promise(7 () =>8 new var Promise: PromiseConstructor
new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>
Creates a new Promise.
Promise(((parameter) resolve: (value: string | PromiseLike<string>) => void
resolve) => {9 const const rl: NodeReadLine.Interface
rl = (alias) module "node:readline"
import NodeReadLine
NodeReadLine.function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)
The `readline.createInterface()` method creates a new `readline.Interface` instance.
```js
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:
```js
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](https://en.wikipedia.org/wiki/End-of-file#EOF_character). To exit without
waiting for user input, call `process.stdin.unref()`.
createInterface({10 (property) ReadLineOptions.input: NodeJS.ReadableStream
input: var process: NodeJS.Process
process.(property) NodeJS.Process.stdin: NodeJS.ReadStream & {
fd: 0;
}
The `process.stdin` property returns a stream connected to`stdin` (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,11 (property) ReadLineOptions.output?: NodeJS.WritableStream | undefined
output: var process: NodeJS.Process
process.(property) NodeJS.Process.stdout: NodeJS.WriteStream & {
fd: 1;
}
The `process.stdout` property returns a stream connected to`stdout` (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`:
```js
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.
stdout12 })13 const rl: NodeReadLine.Interface
rl.(method) 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:
```js
rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
```
Using an `AbortController` to cancel a question.
```js
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);
```
question((parameter) message: string
message, ((parameter) answer: string
answer) => {14 const rl: NodeReadLine.Interface
rl.(method) 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.
close()15 (parameter) resolve: (value: string | PromiseLike<string>) => void
resolve((parameter) answer: string
answer)16 })17 })18 )19
20const const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames = import Effect
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)
gen(function* () {21 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>
make(import Chunk
Chunk.const empty: <string>() => Chunk.Chunk<string>
empty<string>())22 while (true) {23 const const name: string
name = yield* const readLine: (message: string) => Effect.Effect<string>
readLine("Please enter a name or `q` to exit: ")24 if (const name: string
name === "q") {25 break26 }27 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)
update(const ref: Ref.Ref<Chunk.Chunk<string>>
ref, ((parameter) 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`.
append((parameter) state: Chunk.Chunk<string>
state, const name: string
name))28 }29 return yield* import Ref
Ref.const get: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>) => Effect.Effect<Chunk.Chunk<string>, never, never>
get(const ref: Ref.Ref<Chunk.Chunk<string>>
ref)30})31
32import Effect
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 a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames).(method) 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.
then(namespace console
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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
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:
```js
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
```
console.(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log)33/*34Output:35Please enter a name or `q` to exit: Alice36Please enter a name or `q` to exit: Bob37Please enter a name or `q` to exit: q38{39 _id: "Chunk",40 values: [ "Alice", "Bob" ]41}42*/
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:
1import { import Effect
Effect, import Chunk
Chunk, import Ref
Ref, import Fiber
Fiber } from "effect"2import * as (alias) module "node:readline"
import NodeReadLine
NodeReadLine from "node:readline"3
4// Utility to read user input14 collapsed lines
5const const readLine: (message: string) => Effect.Effect<string>
readLine = ((parameter) message: string
message: string): import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<string> =>6 import Effect
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.
The provided function (`thunk`) returns a `Promise` that should never reject.
If the `Promise` does reject, the rejection is treated as a defect.
An optional `AbortSignal` can be provided to allow for interruption of the
wrapped `Promise` API.
promise(7 () =>8 new var Promise: PromiseConstructor
new <string>(executor: (resolve: (value: string | PromiseLike<string>) => void, reject: (reason?: any) => void) => void) => Promise<string>
Creates a new Promise.
Promise(((parameter) resolve: (value: string | PromiseLike<string>) => void
resolve) => {9 const const rl: NodeReadLine.Interface
rl = (alias) module "node:readline"
import NodeReadLine
NodeReadLine.function createInterface(options: NodeReadLine.ReadLineOptions): NodeReadLine.Interface (+1 overload)
The `readline.createInterface()` method creates a new `readline.Interface` instance.
```js
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:
```js
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](https://en.wikipedia.org/wiki/End-of-file#EOF_character). To exit without
waiting for user input, call `process.stdin.unref()`.
createInterface({10 (property) ReadLineOptions.input: NodeJS.ReadableStream
input: var process: NodeJS.Process
process.(property) NodeJS.Process.stdin: NodeJS.ReadStream & {
fd: 0;
}
The `process.stdin` property returns a stream connected to`stdin` (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,11 (property) ReadLineOptions.output?: NodeJS.WritableStream | undefined
output: var process: NodeJS.Process
process.(property) NodeJS.Process.stdout: NodeJS.WriteStream & {
fd: 1;
}
The `process.stdout` property returns a stream connected to`stdout` (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`:
```js
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.
stdout12 })13 const rl: NodeReadLine.Interface
rl.(method) 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:
```js
rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
```
Using an `AbortController` to cancel a question.
```js
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);
```
question((parameter) message: string
message, ((parameter) answer: string
answer) => {14 const rl: NodeReadLine.Interface
rl.(method) 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.
close()15 (parameter) resolve: (value: string | PromiseLike<string>) => void
resolve((parameter) answer: string
answer)16 })17 })18 )19
20const const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames = import Effect
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)
gen(function* () {21 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>
make(import Chunk
Chunk.const empty: <string>() => Chunk.Chunk<string>
empty<string>())22
23 // Fiber 1: Reading names from user input24 const const fiber1: Fiber.RuntimeFiber<void, never>
fiber1 = yield* import Effect
Effect.const fork: <void, never, never>(self: Effect.Effect<void, never, never>) => Effect.Effect<Fiber.RuntimeFiber<void, never>, never, never>
Returns an effect that forks this effect into its own separate fiber,
returning the fiber immediately, without waiting for it to begin executing
the effect.
You can use the `fork` method whenever you want to execute an effect in a
new fiber, concurrently and without "blocking" the fiber executing other
effects. Using fibers can be tricky, so instead of using this method
directly, consider other higher-level methods, such as `raceWith`,
`zipPar`, and so forth.
The fiber returned by this method has methods to interrupt the fiber and to
wait for it to finish executing the effect. See `Fiber` for more
information.
Whenever you use this method to launch a new fiber, the new fiber is
attached to the parent fiber's scope. This means when the parent fiber
terminates, the child fiber will be terminated as well, ensuring that no
fibers leak. This behavior is called "auto supervision", and if this
behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.
fork(25 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {26 while (true) {27 const const name: string
name = yield* const readLine: (message: string) => Effect.Effect<string>
readLine(28 "Please enter a name or `q` to exit: "29 )30 if (const name: string
name === "q") {31 break32 }33 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)
update(const ref: Ref.Ref<Chunk.Chunk<string>>
ref, ((parameter) 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`.
append((parameter) state: Chunk.Chunk<string>
state, const name: string
name))34 }35 })36 )37
38 // Fiber 2: Updating the state with predefined names39 const const fiber2: Fiber.RuntimeFiber<void, never>
fiber2 = yield* import Effect
Effect.const fork: <void, never, never>(self: Effect.Effect<void, never, never>) => Effect.Effect<Fiber.RuntimeFiber<void, never>, never, never>
Returns an effect that forks this effect into its own separate fiber,
returning the fiber immediately, without waiting for it to begin executing
the effect.
You can use the `fork` method whenever you want to execute an effect in a
new fiber, concurrently and without "blocking" the fiber executing other
effects. Using fibers can be tricky, so instead of using this method
directly, consider other higher-level methods, such as `raceWith`,
`zipPar`, and so forth.
The fiber returned by this method has methods to interrupt the fiber and to
wait for it to finish executing the effect. See `Fiber` for more
information.
Whenever you use this method to launch a new fiber, the new fiber is
attached to the parent fiber's scope. This means when the parent fiber
terminates, the child fiber will be terminated as well, ensuring that no
fibers leak. This behavior is called "auto supervision", and if this
behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.
fork(40 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {41 for (const const name: string
name of ["John", "Jane", "Joe", "Tom"]) {42 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)
update(const ref: Ref.Ref<Chunk.Chunk<string>>
ref, ((parameter) 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`.
append((parameter) state: Chunk.Chunk<string>
state, const name: string
name))43 yield* import Effect
Effect.const sleep: (duration: DurationInput) => Effect.Effect<void>
Returns an effect that suspends for the specified duration. This method is
asynchronous, and does not actually block the fiber executing the effect.
sleep("1 second")44 }45 })46 )47 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.
join(const fiber1: Fiber.RuntimeFiber<void, never>
fiber1)48 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.
join(const fiber2: Fiber.RuntimeFiber<void, never>
fiber2)49 return yield* import Ref
Ref.const get: <Chunk.Chunk<string>>(self: Ref.Ref<Chunk.Chunk<string>>) => Effect.Effect<Chunk.Chunk<string>, never, never>
get(const ref: Ref.Ref<Chunk.Chunk<string>>
ref)50})51
52import Effect
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 a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const getNames: Effect.Effect<Chunk.Chunk<string>, never, never>
getNames).(method) 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.
then(namespace console
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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
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:
```js
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
```
console.(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log)53/*54Output:55Please enter a name or `q` to exit: Alice56Please enter a name or `q` to exit: Bob57Please enter a name or `q` to exit: q58{59 _id: "Chunk",60 values: [ ... ]61}62*/