Effect provides different ways to create effects, which are units of computation that encapsulate side effects.
In this guide, we will cover some of the common methods that you can use to create effects.
Why Not Throw Errors?
In traditional programming, when an error occurs, it is often handled by throwing an exception:
However, throwing errors can be problematic. The type signatures of functions do not indicate that they can throw exceptions, making it difficult to reason about potential errors.
To address this issue, Effect introduces dedicated constructors for creating effects that represent both success and failure: Effect.succeed and Effect.fail. These constructors allow you to explicitly handle success and failure cases while leveraging the type system to track errors.
succeed
Creates an Effect that always succeeds with a given value.
Use this function when you need an effect that completes successfully with a specific value
without any errors or external dependencies.
Creates an Effect that always succeeds with a given value.
When to Use
Use this function when you need an effect that completes successfully with a
specific value without any errors or external dependencies.
@see ― fail to create an effect that represents a failure.
@example
// Title: Creating a Successful Effect
import { Effect } from"effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
constsuccess= Effect.succeed(42)
@since ― 2.0.0
succeed(42)
The type of success is Effect<number, never, never>, which means:
It produces a value of type number.
It does not generate any errors (never indicates no errors).
It requires no additional data or dependencies (never indicates no requirements).
┌─── Produces a value of type number
│ ┌─── Does not generate any errors
│ │ ┌─── Requires no dependencies
▼ ▼ ▼
Effect<number, never, never>
fail
Creates an Effect that represents an error that can be recovered from.
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like Effect.catchAll or
Effect.catchTag.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
@example
// Title: Creating a Failed Effect
import { Effect } from"effect"
// ┌─── Effect<never, Error, never>
// ▼
constfailure= Effect.fail(
newError("Operation failed due to network error")
)
@since ― 2.0.0
fail(
6
new
var Error:ErrorConstructor
new (message?:string) => Error
Error("Operation failed due to network error")
7
)
The type of failure is Effect<never, Error, never>, which means:
It never produces a value (never indicates that no successful result will be produced).
It fails with an error, specifically an Error.
It requires no additional data or dependencies (never indicates no requirements).
┌─── Never produces a value
│ ┌─── Fails with an Error
│ │ ┌─── Requires no dependencies
▼ ▼ ▼
Effect<never, Error, never>
Although you can use Error objects with Effect.fail, you can also pass strings, numbers, or more complex objects depending on your error management strategy.
Using “tagged” errors (objects with a _tag field) can help identify error types and works well with standard Effect functions, like Effect.catchTag.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
@example
// Title: Creating a Failed Effect
import { Effect } from"effect"
// ┌─── Effect<never, Error, never>
// ▼
constfailure= Effect.fail(
newError("Operation failed due to network error")
)
@since ― 2.0.0
fail(new
constructor HttpError(): HttpError
HttpError())
Error Tracking
With Effect.succeed and Effect.fail, you can explicitly handle success and failure cases and the type system will ensure that errors are tracked and accounted for.
Example (Rewriting a Division Function)
Here’s how you can rewrite the divide function using Effect, making error handling explicit.
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.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Creates an Effect that always succeeds with a given value.
When to Use
Use this function when you need an effect that completes successfully with a
specific value without any errors or external dependencies.
@see ― fail to create an effect that represents a failure.
@example
// Title: Creating a Successful Effect
import { Effect } from"effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
constsuccess= Effect.succeed(42)
@since ― 2.0.0
succeed(
a: number
a/
b: number
b)
In this example, the divide function indicates in its return type Effect<number, Error> that the operation can either succeed with a number or fail with an Error.
┌─── Produces a value of type number
│ ┌─── Fails with an Error
▼ ▼
Effect<number, Error>
This clear type signature helps ensure that errors are handled properly and that anyone calling the function is aware of the possible outcomes.
Example (Simulating a User Retrieval Operation)
Let’s imagine another scenario where we use Effect.succeed and Effect.fail to model a simple user retrieval operation where the user data is hardcoded, which could be useful in testing scenarios or when mocking data:
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect } from"effect"
2
3
// Define a User type
4
interface
interfaceUser
User {
5
readonly
User.id: number
id:number
6
readonly
User.name: string
name:string
7
}
8
9
// A mocked function to simulate fetching a user from a database
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.
@since ― 2.0.0
@since ― 2.0.0
Effect<
interfaceUser
User,
interfaceError
Error> => {
11
// Normally, you would access a database or API here, but we'll mock it
12
const
constuserDatabase:Record<number, User>
userDatabase:
typeRecord<Kextendskeyofany, T> = { [PinK]:T; }
Construct a type with a set of properties K of type T
Record<number,
interfaceUser
User> = {
13
1: {
User.id: number
id: 1,
User.name: string
name: "John Doe" },
14
2: {
User.id: number
id: 2,
User.name: string
name: "Jane Smith" }
15
}
16
17
// Check if the user exists in our "database" and return appropriately
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
@example
// Title: Creating a Failed Effect
import { Effect } from"effect"
// ┌─── Effect<never, Error, never>
// ▼
constfailure= Effect.fail(
newError("Operation failed due to network error")
)
@since ― 2.0.0
fail(new
var Error:ErrorConstructor
new (message?:string) => Error
Error("User not found"))
23
}
24
}
25
26
// When executed, this will successfully return the user with id 1
In this example, exampleUserEffect, which has the type Effect<User, Error>, will either produce a User object or an Error, depending on whether the user exists in the mocked database.
For a deeper dive into managing errors in your applications, refer to the Error Management Guide.
Modeling Synchronous Effects
In JavaScript, you can delay the execution of synchronous computations using “thunks”.
Thunks are useful for delaying the computation of a value until it is needed.
To model synchronous side effects, Effect provides the Effect.sync and Effect.try constructors, which accept a thunk.
sync
Creates an Effect that represents a synchronous side-effectful computation.
Use Effect.sync when you are sure the operation will not fail.
The provided function (thunk) must not throw errors; 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 Effect.catchAllDefect.
This feature ensures that even unexpected failures in your application are not lost and can be handled appropriately.
Example (Logging a Message)
In the example below, Effect.sync is used to defer the side-effect of writing to the console.
Creates an Effect that represents a synchronous side-effectful computation.
When to Use
Use sync when you are sure the operation will not fail.
Details
The provided function (thunk) must not throw errors; 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
.
@see ― try_try for a version that can handle failures.
@example
// Title: Logging a Message
import { Effect } from"effect"
constlog= (message:string) =>
Effect.sync(() => {
console.log(message) // side effect
})
// ┌─── Effect<void, never, never>
// ▼
constprogram=log("Hello, World!")
@since ― 2.0.0
sync(() => {
5
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
The side effect (logging to the console) encapsulated within program won’t occur until the effect is explicitly run (see the Running Effects section for more details). This allows you to define side effects at one point in your code and control when they are activated, improving manageability and predictability of side effects in larger applications.
try
Creates an Effect that represents a synchronous computation that might fail.
In situations where you need to perform synchronous operations that might fail, such as parsing JSON, you can use the Effect.try constructor.
This constructor is designed to handle operations that could throw exceptions by capturing those exceptions and transforming them into manageable errors.
Example (Safe JSON Parsing)
Suppose you have a function that attempts to parse a JSON string. This operation can fail and throw an error if the input string is not properly formatted as JSON:
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON.
JSON.parse(text: string, reviver?: (this:any, key:string, value:any) => any): any
Converts a JavaScript Object Notation (JSON) string into an object.
@param ― text A valid JSON string.
@param ― reviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.
parse is a function that creates an effect encapsulating the JSON parsing operation.
If JSON.parse(input) throws an error due to invalid input, Effect.try catches this error and the effect represented by program will fail with an UnknownException. This ensures that errors are not silently ignored but are instead handled within the structured flow of effects.
Customizing Error Handling
You might want to transform the caught exception into a more specific error or perform additional operations when catching an error. Effect.try supports an overload that allows you to specify how caught exceptions should be transformed:
An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.
JSON.
JSON.parse(text: string, reviver?: (this:any, key:string, value:any) => any): any
Converts a JavaScript Object Notation (JSON) string into an object.
@param ― text A valid JSON string.
@param ― reviver A function that transforms the results. This function is called for each member of the object.
If a member contains nested objects, the nested objects are transformed before the parent object is.
You can think of this as a similar pattern to the traditional try-catch block in JavaScript:
try {
returnJSON.parse(input)
} catch (unknown) {
thrownewError(`something went wrong ${unknown}`)
}
Modeling Asynchronous Effects
In traditional programming, we often use Promises to handle asynchronous computations. However, dealing with errors in promises can be problematic. By default, Promise<Value> only provides the type Value for the resolved value, which means errors are not reflected in the type system. This limits the expressiveness and makes it challenging to handle and track errors effectively.
To overcome these limitations, Effect introduces dedicated constructors for creating effects that represent both success and failure in an asynchronous context: Effect.promise and Effect.tryPromise. These constructors allow you to explicitly handle success and failure cases while leveraging the type system to track errors.
promise
Creates an Effect that represents an asynchronous computation guaranteed to succeed.
Use Effect.promise when you are sure the operation will not reject.
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 Effect.catchAllDefect.
This feature ensures that even unexpected failures in your application are not lost and can be handled appropriately.
Creates an Effect that represents an asynchronous computation guaranteed to
succeed.
When to Use
Use promise when you are sure the operation will not reject.
Details
The provided function (thunk) returns a Promise that should never reject; if it does, the error
will be treated as a "defect".
This defect is not a standard error but indicates a flaw in the logic that
was expected to be error-free. You can think of it similar to an unexpected
crash in the program, which can be further managed or logged using tools like
catchAllDefect
.
Interruptions
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
@see ― tryPromise for a version that can handle failures.
new <string>(executor: (resolve: (value:string|PromiseLike<string>) =>void, reject: (reason?:any) =>void) =>void) =>Promise<string>
Creates a new Promise.
@param ― executor 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.
Schedules execution of a one-time callback after delay milliseconds.
The callback will likely not be invoked in precisely delay milliseconds.
Node.js makes no guarantees about the exact timing of when callbacks will fire,
nor of their ordering. The callback will be called as close as possible to the
time specified.
When delay is larger than 2147483647 or less than 1, the delay will be set to 1. Non-integer delays are truncated to an integer.
If callback is not a function, a TypeError will be thrown.
This method has a custom variant for promises that is available using timersPromises.setTimeout().
@since ― v0.0.1
@param ― callback The function to call when the timer elapses.
@param ― delay The number of milliseconds to wait before calling the callback.
@param ― args Optional arguments to pass when the callback is called.
The program value has the type Effect<string, never, never> and can be interpreted as an effect that:
succeeds with a value of type string
does not produce any expected error (never)
does not require any context (never)
tryPromise
Creates an Effect that represents an asynchronous computation that might fail.
Unlike Effect.promise, this constructor is suitable when the underlying Promise might reject.
It provides a way to catch errors and handle them appropriately.
By default if an error occurs, it will be caught and propagated to the error channel as as an UnknownException.
Creates an Effect that represents an asynchronous computation that might
fail.
When to Use
In situations where you need to perform asynchronous operations that might
fail, such as fetching data from an API, you can use the tryPromise
constructor. This constructor is designed to handle operations that could
throw exceptions by capturing those exceptions and transforming them into
manageable errors.
Error Handling
There are two ways to handle errors with tryPromise:
If you don't provide a catch function, the error is caught and the
effect fails with an UnknownException.
If you provide a catch function, the error is caught and the catch
function maps it to an error of type E.
Interruptions
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
@see ― promise if the effectful computation is asynchronous and does not throw errors.
@example
// Title: Fetching a TODO Item
import { Effect } from"effect"
constgetTodo= (id:number) =>
// Will catch any errors and propagate them as UnknownException
Creates an Effect that represents an asynchronous computation that might
fail.
When to Use
In situations where you need to perform asynchronous operations that might
fail, such as fetching data from an API, you can use the tryPromise
constructor. This constructor is designed to handle operations that could
throw exceptions by capturing those exceptions and transforming them into
manageable errors.
Error Handling
There are two ways to handle errors with tryPromise:
If you don't provide a catch function, the error is caught and the
effect fails with an UnknownException.
If you provide a catch function, the error is caught and the catch
function maps it to an error of type E.
Interruptions
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
@see ― promise if the effectful computation is asynchronous and does not throw errors.
@example
// Title: Fetching a TODO Item
import { Effect } from"effect"
constgetTodo= (id:number) =>
// Will catch any errors and propagate them as UnknownException
Creates an Effect from a callback-based asynchronous function.
Sometimes you have to work with APIs that don’t support async/await or Promise and instead use the callback style.
To handle callback-based APIs, Effect provides the Effect.async constructor.
Example (Wrapping a Callback API)
Let’s wrap the readFile function from Node.js’s fs module into an Effect-based API (make sure @types/node is installed):
Creates an Effect from a callback-based asynchronous function.
When to Use
Use async when dealing with APIs that use callback-style instead of
async/await or Promise.
Details
The resume function:
Must be called exactly once. Any additional calls will be ignored.
Can return an optional Effect that will be run if the Fiber executing
this Effect is interrupted. This can be useful in scenarios where you
need to handle resource cleanup if the operation is interrupted.
Can receive an AbortSignal to handle interruption if needed.
The FiberId of the fiber that may complete the async callback may also be
specified using the blockingOn argument. This is called the "blocking
fiber" because it suspends the fiber executing the async effect (i.e.
semantically blocks the fiber from making progress). Specifying this fiber id
in cases where it is known will improve diagnostics, but not affect the
behavior of the returned effect.
@example
// Title: Wrapping a Callback API
import { Effect } from"effect"
import*as NodeFS from"node:fs"
constreadFile= (filename:string) =>
Effect.async<Buffer, Error>((resume) => {
NodeFS.readFile(filename, (error, data) => {
if (error) {
// Resume with a failed Effect if an error occurs
resume(Effect.fail(error))
} else {
// Resume with a succeeded Effect if successful
resume(Effect.succeed(data))
}
})
})
// ┌─── Effect<Buffer, Error, never>
// ▼
constprogram=readFile("example.txt")
@example
// Title: Handling Interruption with Cleanup
import { Effect, Fiber } from "effect"
import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a file
const writeFileWithCleanup = (filename: string, data: string) =>
Effect.async<void, Error>((resume) => {
const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file
writeStream.write(data)
// When the stream is finished, resume with success
// Handle interruption by returning a cleanup effect
return Effect.sync(() => {
console.log(`Cleaning up ${filename}`)
NodeFS.unlinkSync(filename)
})
})
const program = Effect.gen(function* () {
const fiber = yield* Effect.fork(
writeFileWithCleanup("example.txt", "Some long data...")
)
// Simulate interrupting the fiber after 1 second
yield* Effect.sleep("1 second")
yield* Fiber.interrupt(fiber) // This will trigger the cleanup
})
// Run the program
Effect.runPromise(program)
// Output:
// Cleaning up example.txt
@example
// Title: Handling Interruption with AbortSignal
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignal
const interruptibleTask = Effect.async<void, Error>((resume, signal) => {
// Handle interruption
signal.addEventListener("abort", () => {
console.log("Abort signal received")
clearTimeout(timeoutId)
})
Asynchronously reads the entire contents of a file.
@param ― path A path to a file. If a URL is provided, it must use the file: protocol.
If a file descriptor is provided, the underlying file will not be closed automatically.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
In the above example, we manually annotate the types when calling Effect.async:
Effect.async<Buffer, Error>((resume) => {
// ...
})
because TypeScript cannot infer the type parameters for a callback
based on the return value inside the callback body. Annotating the types ensures that the values provided to resume match the expected types.
The resume function inside Effect.async should be called exactly once. Calling it more than once will result in the extra calls being ignored.
Creates an Effect from a callback-based asynchronous function.
When to Use
Use async when dealing with APIs that use callback-style instead of
async/await or Promise.
Details
The resume function:
Must be called exactly once. Any additional calls will be ignored.
Can return an optional Effect that will be run if the Fiber executing
this Effect is interrupted. This can be useful in scenarios where you
need to handle resource cleanup if the operation is interrupted.
Can receive an AbortSignal to handle interruption if needed.
The FiberId of the fiber that may complete the async callback may also be
specified using the blockingOn argument. This is called the "blocking
fiber" because it suspends the fiber executing the async effect (i.e.
semantically blocks the fiber from making progress). Specifying this fiber id
in cases where it is known will improve diagnostics, but not affect the
behavior of the returned effect.
@example
// Title: Wrapping a Callback API
import { Effect } from"effect"
import*as NodeFS from"node:fs"
constreadFile= (filename:string) =>
Effect.async<Buffer, Error>((resume) => {
NodeFS.readFile(filename, (error, data) => {
if (error) {
// Resume with a failed Effect if an error occurs
resume(Effect.fail(error))
} else {
// Resume with a succeeded Effect if successful
resume(Effect.succeed(data))
}
})
})
// ┌─── Effect<Buffer, Error, never>
// ▼
constprogram=readFile("example.txt")
@example
// Title: Handling Interruption with Cleanup
import { Effect, Fiber } from "effect"
import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a file
const writeFileWithCleanup = (filename: string, data: string) =>
Effect.async<void, Error>((resume) => {
const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file
writeStream.write(data)
// When the stream is finished, resume with success
// Handle interruption by returning a cleanup effect
return Effect.sync(() => {
console.log(`Cleaning up ${filename}`)
NodeFS.unlinkSync(filename)
})
})
const program = Effect.gen(function* () {
const fiber = yield* Effect.fork(
writeFileWithCleanup("example.txt", "Some long data...")
)
// Simulate interrupting the fiber after 1 second
yield* Effect.sleep("1 second")
yield* Fiber.interrupt(fiber) // This will trigger the cleanup
})
// Run the program
Effect.runPromise(program)
// Output:
// Cleaning up example.txt
@example
// Title: Handling Interruption with AbortSignal
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignal
const interruptibleTask = Effect.async<void, Error>((resume, signal) => {
// Handle interruption
signal.addEventListener("abort", () => {
console.log("Abort signal received")
clearTimeout(timeoutId)
})
Executes an effect and returns the result as a Promise.
When to Use
Use runPromise when you need to execute an effect and work with the
result using Promise syntax, typically for compatibility with other
promise-based code.
If the effect succeeds, the promise will resolve with the result. If the
effect fails, the promise will reject with an error.
@see ― runPromiseExit for a version that returns an Exit type instead of rejecting.
@example
// Title: Running a Successful Effect as a Promise
Attaches callbacks for the resolution and/or rejection of the Promise.
@param ― onfulfilled The callback to execute when the Promise is resolved.
@param ― onrejected The callback to execute when the Promise is rejected.
@returns ― A 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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
For more advanced use cases, resume can optionally return an Effect that will be executed if the fiber running this effect is interrupted. This can be useful in scenarios where you need to handle resource cleanup if the operation is interrupted.
Example (Handling Interruption with Cleanup)
In this example:
The writeFileWithCleanup function writes data to a file.
If the fiber running this effect is interrupted, the cleanup effect (which deletes the file) is executed.
This ensures that resources like open file handles are cleaned up properly when the operation is canceled.
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect,
import Fiber
Fiber } from"effect"
2
import*as
module"node:fs"
NodeFSfrom"node:fs"
3
4
// Simulates a long-running operation to write to a file
Creates an Effect from a callback-based asynchronous function.
When to Use
Use async when dealing with APIs that use callback-style instead of
async/await or Promise.
Details
The resume function:
Must be called exactly once. Any additional calls will be ignored.
Can return an optional Effect that will be run if the Fiber executing
this Effect is interrupted. This can be useful in scenarios where you
need to handle resource cleanup if the operation is interrupted.
Can receive an AbortSignal to handle interruption if needed.
The FiberId of the fiber that may complete the async callback may also be
specified using the blockingOn argument. This is called the "blocking
fiber" because it suspends the fiber executing the async effect (i.e.
semantically blocks the fiber from making progress). Specifying this fiber id
in cases where it is known will improve diagnostics, but not affect the
behavior of the returned effect.
@example
// Title: Wrapping a Callback API
import { Effect } from"effect"
import*as NodeFS from"node:fs"
constreadFile= (filename:string) =>
Effect.async<Buffer, Error>((resume) => {
NodeFS.readFile(filename, (error, data) => {
if (error) {
// Resume with a failed Effect if an error occurs
resume(Effect.fail(error))
} else {
// Resume with a succeeded Effect if successful
resume(Effect.succeed(data))
}
})
})
// ┌─── Effect<Buffer, Error, never>
// ▼
constprogram=readFile("example.txt")
@example
// Title: Handling Interruption with Cleanup
import { Effect, Fiber } from "effect"
import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a file
const writeFileWithCleanup = (filename: string, data: string) =>
Effect.async<void, Error>((resume) => {
const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file
writeStream.write(data)
// When the stream is finished, resume with success
// Handle interruption by returning a cleanup effect
return Effect.sync(() => {
console.log(`Cleaning up ${filename}`)
NodeFS.unlinkSync(filename)
})
})
const program = Effect.gen(function* () {
const fiber = yield* Effect.fork(
writeFileWithCleanup("example.txt", "Some long data...")
)
// Simulate interrupting the fiber after 1 second
yield* Effect.sleep("1 second")
yield* Fiber.interrupt(fiber) // This will trigger the cleanup
})
// Run the program
Effect.runPromise(program)
// Output:
// Cleaning up example.txt
@example
// Title: Handling Interruption with AbortSignal
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignal
const interruptibleTask = Effect.async<void, Error>((resume, signal) => {
// Handle interruption
signal.addEventListener("abort", () => {
console.log("Abort signal received")
clearTimeout(timeoutId)
})
options may also include a start option to allow writing data at some
position past the beginning of the file, allowed values are in the
[0, Number.MAX_SAFE_INTEGER] range. Modifying a file rather than
replacing it may require the flags option to be set to r+ rather than the
default w. The encoding can be any one of those accepted by Buffer.
If autoClose is set to true (default behavior) on 'error' or 'finish' the file descriptor will be closed automatically. If autoClose is false,
then the file descriptor won't be closed, even if there's an error.
It is the application's responsibility to close it and make sure there's no
file descriptor leak.
By default, the stream will emit a 'close' event after it has been
destroyed. Set the emitClose option to false to change this behavior.
By providing the fs option it is possible to override the corresponding fs implementations for open, write, writev, and close. Overriding write() without writev() can reduce
performance as some optimizations (_writev())
will be disabled. When providing the fs option, overrides for at least one of write and writev are required. If no fd option is supplied, an override
for open is also required. If autoClose is true, an override for close is also required.
Like fs.ReadStream, if fd is specified, fs.WriteStream will ignore the path argument and will use the specified file descriptor. This means that no 'open' event will be
emitted. fd should be blocking; non-blocking fds
should be passed to net.Socket.
If options is a string, then it specifies the encoding.
The writable.write() method writes some data to the stream, and calls the
supplied callback once the data has been fully handled. If an error
occurs, the callback will be called with the error as its
first argument. The callback is called asynchronously and before 'error' is
emitted.
The return value is true if the internal buffer is less than the highWaterMark configured when the stream was created after admitting chunk.
If false is returned, further attempts to write data to the stream should
stop until the 'drain' event is emitted.
While a stream is not draining, calls to write() will buffer chunk, and
return false. Once all currently buffered chunks are drained (accepted for
delivery by the operating system), the 'drain' event will be emitted.
Once write() returns false, do not write more chunks
until the 'drain' event is emitted. While calling write() on a stream that
is not draining is allowed, Node.js will buffer all written chunks until
maximum memory usage occurs, at which point it will abort unconditionally.
Even before it aborts, high memory usage will cause poor garbage collector
performance and high RSS (which is not typically released back to the system,
even after the memory is no longer required). Since TCP sockets may never
drain if the remote peer does not read the data, writing a socket that is
not draining may lead to a remotely exploitable vulnerability.
Writing data while the stream is not draining is particularly
problematic for a Transform, because the Transform streams are paused
by default until they are piped or a 'data' or 'readable' event handler
is added.
If the data to be written can be generated or fetched on demand, it is
recommended to encapsulate the logic into a Readable and use
pipe
. However, if calling write() is preferred, it is
possible to respect backpressure and avoid memory issues using the 'drain' event:
functionwrite(data, cb) {
if (!stream.write(data)) {
stream.once('drain', cb);
} else {
process.nextTick(cb);
}
}
// Wait for cb to be called before doing any other write.
write('hello', () => {
console.log('Write completed, do more writes now.');
});
A Writable stream in object mode will always ignore the encoding argument.
@since ― v0.9.4
@param ― chunk Optional data to write. For streams not operating in object mode, chunk must be a {string}, {Buffer},
{TypedArray} or {DataView}. For object mode streams, chunk may be any JavaScript value other than null.
@param ― encoding The encoding, if chunk is a string.
@param ― callback Callback for when this chunk of data is flushed.
write(
data: string
data)
11
12
// When the stream is finished, resume with success
Adds the listener function to the end of the listeners array for the event
named eventName. No checks are made to see if the listener has already
been added. Multiple calls passing the same combination of eventName and
listener will result in the listener being added, and called, multiple times.
server.on('connection', (stream) => {
console.log('someone connected!');
});
Returns a reference to the EventEmitter, so that calls can be chained.
By default, event listeners are invoked in the order they are added. The emitter.prependListener() method can be used as an alternative to add the
event listener to the beginning of the listeners array.
Adds the listener function to the end of the listeners array for the event
named eventName. No checks are made to see if the listener has already
been added. Multiple calls passing the same combination of eventName and
listener will result in the listener being added, and called, multiple times.
server.on('connection', (stream) => {
console.log('someone connected!');
});
Returns a reference to the EventEmitter, so that calls can be chained.
By default, event listeners are invoked in the order they are added. The emitter.prependListener() method can be used as an alternative to add the
event listener to the beginning of the listeners array.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
@example
// Title: Creating a Failed Effect
import { Effect } from"effect"
// ┌─── Effect<never, Error, never>
// ▼
constfailure= Effect.fail(
newError("Operation failed due to network error")
)
@since ― 2.0.0
fail(
err: Error
err)))
17
18
// Handle interruption by returning a cleanup effect
Creates an Effect that represents a synchronous side-effectful computation.
When to Use
Use sync when you are sure the operation will not fail.
Details
The provided function (thunk) must not throw errors; 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
.
@see ― try_try for a version that can handle failures.
@example
// Title: Logging a Message
import { Effect } from"effect"
constlog= (message:string) =>
Effect.sync(() => {
console.log(message) // side effect
})
// ┌─── Effect<void, never, never>
// ▼
constprogram=log("Hello, World!")
@since ― 2.0.0
sync(() => {
20
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
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.
Interrupts the fiber from whichever fiber is calling this method. If the
fiber has already exited, the returned effect will resume immediately.
Otherwise, the effect will resume when the fiber exits.
Executes an effect and returns the result as a Promise.
When to Use
Use runPromise when you need to execute an effect and work with the
result using Promise syntax, typically for compatibility with other
promise-based code.
If the effect succeeds, the promise will resolve with the result. If the
effect fails, the promise will reject with an error.
@see ― runPromiseExit for a version that returns an Exit type instead of rejecting.
@example
// Title: Running a Successful Effect as a Promise
Creates an Effect from a callback-based asynchronous function.
When to Use
Use async when dealing with APIs that use callback-style instead of
async/await or Promise.
Details
The resume function:
Must be called exactly once. Any additional calls will be ignored.
Can return an optional Effect that will be run if the Fiber executing
this Effect is interrupted. This can be useful in scenarios where you
need to handle resource cleanup if the operation is interrupted.
Can receive an AbortSignal to handle interruption if needed.
The FiberId of the fiber that may complete the async callback may also be
specified using the blockingOn argument. This is called the "blocking
fiber" because it suspends the fiber executing the async effect (i.e.
semantically blocks the fiber from making progress). Specifying this fiber id
in cases where it is known will improve diagnostics, but not affect the
behavior of the returned effect.
@example
// Title: Wrapping a Callback API
import { Effect } from"effect"
import*as NodeFS from"node:fs"
constreadFile= (filename:string) =>
Effect.async<Buffer, Error>((resume) => {
NodeFS.readFile(filename, (error, data) => {
if (error) {
// Resume with a failed Effect if an error occurs
resume(Effect.fail(error))
} else {
// Resume with a succeeded Effect if successful
resume(Effect.succeed(data))
}
})
})
// ┌─── Effect<Buffer, Error, never>
// ▼
constprogram=readFile("example.txt")
@example
// Title: Handling Interruption with Cleanup
import { Effect, Fiber } from "effect"
import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a file
const writeFileWithCleanup = (filename: string, data: string) =>
Effect.async<void, Error>((resume) => {
const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file
writeStream.write(data)
// When the stream is finished, resume with success
// Handle interruption by returning a cleanup effect
return Effect.sync(() => {
console.log(`Cleaning up ${filename}`)
NodeFS.unlinkSync(filename)
})
})
const program = Effect.gen(function* () {
const fiber = yield* Effect.fork(
writeFileWithCleanup("example.txt", "Some long data...")
)
// Simulate interrupting the fiber after 1 second
yield* Effect.sleep("1 second")
yield* Fiber.interrupt(fiber) // This will trigger the cleanup
})
// Run the program
Effect.runPromise(program)
// Output:
// Cleaning up example.txt
@example
// Title: Handling Interruption with AbortSignal
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignal
const interruptibleTask = Effect.async<void, Error>((resume, signal) => {
// Handle interruption
signal.addEventListener("abort", () => {
console.log("Abort signal received")
clearTimeout(timeoutId)
})
Adds a new handler for the type event. Any given listener is added only once per type and per capture option value.
If the once option is true, the listener is removed after the next time a type event is dispatched.
The capture option is not used by Node.js in any functional way other than tracking registered event listeners per the EventTarget specification.
Specifically, the capture option is used as part of the key when registering a listener.
Any individual listener may be added once with capture = false, and once with capture = true.
addEventListener("abort", () => {
7
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Schedules execution of a one-time callback after delay milliseconds.
The callback will likely not be invoked in precisely delay milliseconds.
Node.js makes no guarantees about the exact timing of when callbacks will fire,
nor of their ordering. The callback will be called as close as possible to the
time specified.
When delay is larger than 2147483647 or less than 1, the delay will be set to 1. Non-integer delays are truncated to an integer.
If callback is not a function, a TypeError will be thrown.
This method has a custom variant for promises that is available using timersPromises.setTimeout().
@since ― v0.0.1
@param ― callback The function to call when the timer elapses.
@param ― delay The number of milliseconds to wait before calling the callback.
@param ― args Optional arguments to pass when the callback is called.
setTimeout(() => {
13
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
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.
Interrupts the fiber from whichever fiber is calling this method. If the
fiber has already exited, the returned effect will resume immediately.
Otherwise, the effect will resume when the fiber exits.
Executes an effect and returns the result as a Promise.
When to Use
Use runPromise when you need to execute an effect and work with the
result using Promise syntax, typically for compatibility with other
promise-based code.
If the effect succeeds, the promise will resolve with the result. If the
effect fails, the promise will reject with an error.
@see ― runPromiseExit for a version that returns an Exit type instead of rejecting.
@example
// Title: Running a Successful Effect as a Promise
//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
@since ― 2.0.0
runPromise(
constprogram:Effect.Effect<void, never, never>
program)
27
/*
28
Output:
29
Abort signal received
30
*/
Suspended Effects
Effect.suspend is used to delay the creation of an effect.
It allows you to defer the evaluation of an effect until it is actually needed.
The Effect.suspend function takes a thunk that represents the effect, and it wraps it in a suspended effect.
Let’s explore some common scenarios where Effect.suspend proves useful.
Lazy Evaluation
When you want to defer the evaluation of an effect until it is required. This can be useful for optimizing the execution of effects, especially when they are not always needed or when their computation is expensive.
Also, when effects with side effects or scoped captures are created, use Effect.suspend to re-execute on each invocation.
Delays the creation of an Effect until it is actually needed.
When to Use
Use suspend when you need to defer the evaluation of an effect until it is required. This is particularly useful for optimizing expensive computations, managing circular dependencies, or resolving type inference issues.
Details
suspend takes a thunk that represents the effect and wraps it in a suspended effect. This means the effect will not be created until it is explicitly needed, which is helpful in various scenarios:
Lazy Evaluation: Helps optimize performance by deferring computations, especially when the effect might not be needed, or when its computation is expensive. This also ensures that any side effects or scoped captures are re-executed on each invocation.
Handling Circular Dependencies: Useful in managing circular dependencies, such as recursive functions that need to avoid eager evaluation to prevent stack overflow.
Unifying Return Types: Can help TypeScript unify return types in situations where multiple branches of logic return different effects, simplifying type inference.
Creates an Effect that always succeeds with a given value.
When to Use
Use this function when you need an effect that completes successfully with a
specific value without any errors or external dependencies.
@see ― fail to create an effect that represents a failure.
@example
// Title: Creating a Successful Effect
import { Effect } from"effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
constsuccess= Effect.succeed(42)
@since ― 2.0.0
succeed(
let i:number
i++))
8
9
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Executes an effect synchronously, running it immediately and returning the
result.
When to Use
Use runSync to run an effect that does not fail and does not include
any asynchronous operations.
If the effect fails or involves asynchronous work, it will throw an error,
and execution will stop where the failure or async operation occurs.
@see ― runSyncExit for a version that returns an Exit type instead of
throwing an error.
@example
// Title: Synchronous Logging
import { Effect } from"effect"
constprogram= Effect.sync(() => {
console.log("Hello, World!")
return1
})
constresult= Effect.runSync(program)
// Output: Hello, World!
console.log(result)
// Output: 1
@example
// Title: Incorrect Usage with Failing or Async Effects
import { Effect } from "effect"
try {
// Attempt to run an effect that fails
Effect.runSync(Effect.fail("my error"))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) Error: my error
try {
// Attempt to run an effect that involves async work
Effect.runSync(Effect.promise(() => Promise.resolve(1)))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) AsyncFiberException: Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work
@since ― 2.0.0
runSync(
constbad:Effect.Effect<number, never, never>
bad)) // Output: 0
10
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Executes an effect synchronously, running it immediately and returning the
result.
When to Use
Use runSync to run an effect that does not fail and does not include
any asynchronous operations.
If the effect fails or involves asynchronous work, it will throw an error,
and execution will stop where the failure or async operation occurs.
@see ― runSyncExit for a version that returns an Exit type instead of
throwing an error.
@example
// Title: Synchronous Logging
import { Effect } from"effect"
constprogram= Effect.sync(() => {
console.log("Hello, World!")
return1
})
constresult= Effect.runSync(program)
// Output: Hello, World!
console.log(result)
// Output: 1
@example
// Title: Incorrect Usage with Failing or Async Effects
import { Effect } from "effect"
try {
// Attempt to run an effect that fails
Effect.runSync(Effect.fail("my error"))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) Error: my error
try {
// Attempt to run an effect that involves async work
Effect.runSync(Effect.promise(() => Promise.resolve(1)))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) AsyncFiberException: Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work
@since ― 2.0.0
runSync(
constbad:Effect.Effect<number, never, never>
bad)) // Output: 0
11
12
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Executes an effect synchronously, running it immediately and returning the
result.
When to Use
Use runSync to run an effect that does not fail and does not include
any asynchronous operations.
If the effect fails or involves asynchronous work, it will throw an error,
and execution will stop where the failure or async operation occurs.
@see ― runSyncExit for a version that returns an Exit type instead of
throwing an error.
@example
// Title: Synchronous Logging
import { Effect } from"effect"
constprogram= Effect.sync(() => {
console.log("Hello, World!")
return1
})
constresult= Effect.runSync(program)
// Output: Hello, World!
console.log(result)
// Output: 1
@example
// Title: Incorrect Usage with Failing or Async Effects
import { Effect } from "effect"
try {
// Attempt to run an effect that fails
Effect.runSync(Effect.fail("my error"))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) Error: my error
try {
// Attempt to run an effect that involves async work
Effect.runSync(Effect.promise(() => Promise.resolve(1)))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) AsyncFiberException: Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work
@since ― 2.0.0
runSync(
constgood:Effect.Effect<number, never, never>
good)) // Output: 1
13
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Executes an effect synchronously, running it immediately and returning the
result.
When to Use
Use runSync to run an effect that does not fail and does not include
any asynchronous operations.
If the effect fails or involves asynchronous work, it will throw an error,
and execution will stop where the failure or async operation occurs.
@see ― runSyncExit for a version that returns an Exit type instead of
throwing an error.
@example
// Title: Synchronous Logging
import { Effect } from"effect"
constprogram= Effect.sync(() => {
console.log("Hello, World!")
return1
})
constresult= Effect.runSync(program)
// Output: Hello, World!
console.log(result)
// Output: 1
@example
// Title: Incorrect Usage with Failing or Async Effects
import { Effect } from "effect"
try {
// Attempt to run an effect that fails
Effect.runSync(Effect.fail("my error"))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) Error: my error
try {
// Attempt to run an effect that involves async work
Effect.runSync(Effect.promise(() => Promise.resolve(1)))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) AsyncFiberException: Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work
@since ― 2.0.0
runSync(
constgood:Effect.Effect<number, never, never>
good)) // Output: 2
In this example, bad is the result of calling Effect.succeed(i++) a single time, which increments the scoped variable but returns its original value. Effect.runSync(bad) does not result in any new computation, because Effect.succeed(i++) has already been called. On the other hand, each time Effect.runSync(good) is called, the thunk passed to Effect.suspend() will be executed, outputting the scoped variable’s most recent value.
Handling Circular Dependencies
Effect.suspend is helpful in managing circular dependencies between effects, where one effect depends on another, and vice versa.
For example it’s fairly common for Effect.suspend to be used in recursive functions to escape an eager call.
Example (Recursive Fibonacci)
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect } from"effect"
2
3
const
constblowsUp: (n:number) =>Effect.Effect<number>
blowsUp= (
n: number
n:number):
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect.
interfaceEffect<outA, outE=never, outR=never>
The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
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.
Delays the creation of an Effect until it is actually needed.
When to Use
Use suspend when you need to defer the evaluation of an effect until it is required. This is particularly useful for optimizing expensive computations, managing circular dependencies, or resolving type inference issues.
Details
suspend takes a thunk that represents the effect and wraps it in a suspended effect. This means the effect will not be created until it is explicitly needed, which is helpful in various scenarios:
Lazy Evaluation: Helps optimize performance by deferring computations, especially when the effect might not be needed, or when its computation is expensive. This also ensures that any side effects or scoped captures are re-executed on each invocation.
Handling Circular Dependencies: Useful in managing circular dependencies, such as recursive functions that need to avoid eager evaluation to prevent stack overflow.
Unifying Return Types: Can help TypeScript unify return types in situations where multiple branches of logic return different effects, simplifying type inference.
Delays the creation of an Effect until it is actually needed.
When to Use
Use suspend when you need to defer the evaluation of an effect until it is required. This is particularly useful for optimizing expensive computations, managing circular dependencies, or resolving type inference issues.
Details
suspend takes a thunk that represents the effect and wraps it in a suspended effect. This means the effect will not be created until it is explicitly needed, which is helpful in various scenarios:
Lazy Evaluation: Helps optimize performance by deferring computations, especially when the effect might not be needed, or when its computation is expensive. This also ensures that any side effects or scoped captures are re-executed on each invocation.
Handling Circular Dependencies: Useful in managing circular dependencies, such as recursive functions that need to avoid eager evaluation to prevent stack overflow.
Unifying Return Types: Can help TypeScript unify return types in situations where multiple branches of logic return different effects, simplifying type inference.
// Title: Using Effect.suspend to Help TypeScript Infer Types
import { Effect } from "effect"
// Without suspend, TypeScript may struggle with type inference.
// Inferred type:
// (a: number, b: number) =>
// Effect<never, Error, never> | Effect<number, never, never>
const withoutSuspend = (a: number, b: number) =>
b === 0
? Effect.fail(new Error("Cannot divide by zero"))
: Effect.succeed(a / b)
// Using suspend to unify return types.
// Inferred type:
// (a: number, b: number) => Effect<number, Error, never>
const withSuspend = (a: number, b: number) =>
Effect.suspend(() =>
b === 0
? Effect.fail(new Error("Cannot divide by zero"))
: Effect.succeed(a / b)
)
@since ― 2.0.0
suspend(() =>
constallGood: (n:number) =>Effect.Effect<number>
allGood(
n: number
n-2)),
17
(
a: number
a,
b: number
b) =>
a: number
a+
b: number
b
18
)
19
20
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(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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()).
Executes an effect synchronously, running it immediately and returning the
result.
When to Use
Use runSync to run an effect that does not fail and does not include
any asynchronous operations.
If the effect fails or involves asynchronous work, it will throw an error,
and execution will stop where the failure or async operation occurs.
@see ― runSyncExit for a version that returns an Exit type instead of
throwing an error.
@example
// Title: Synchronous Logging
import { Effect } from"effect"
constprogram= Effect.sync(() => {
console.log("Hello, World!")
return1
})
constresult= Effect.runSync(program)
// Output: Hello, World!
console.log(result)
// Output: 1
@example
// Title: Incorrect Usage with Failing or Async Effects
import { Effect } from "effect"
try {
// Attempt to run an effect that fails
Effect.runSync(Effect.fail("my error"))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) Error: my error
try {
// Attempt to run an effect that involves async work
Effect.runSync(Effect.promise(() => Promise.resolve(1)))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) AsyncFiberException: Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work
@since ― 2.0.0
runSync(
constallGood: (n:number) =>Effect.Effect<number>
allGood(32))) // Output: 3524578
The blowsUp function creates a recursive Fibonacci sequence without deferring execution. Each call to blowsUp triggers further immediate recursive calls, rapidly increasing the JavaScript call stack size.
Conversely, allGood avoids stack overflow by using Effect.suspend to defer the recursive calls. This mechanism doesn’t immediately execute the recursive effects but schedules them to be run later, thus keeping the call stack shallow and preventing a crash.
Unifying Return Type
In situations where TypeScript struggles to unify the returned effect type, Effect.suspend can be employed to resolve this issue.
Example (Using Effect.suspend to Help TypeScript Infer Types)
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect } from"effect"
2
3
/*
4
Without suspend, TypeScript may struggle with type inference.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Delays the creation of an Effect until it is actually needed.
When to Use
Use suspend when you need to defer the evaluation of an effect until it is required. This is particularly useful for optimizing expensive computations, managing circular dependencies, or resolving type inference issues.
Details
suspend takes a thunk that represents the effect and wraps it in a suspended effect. This means the effect will not be created until it is explicitly needed, which is helpful in various scenarios:
Lazy Evaluation: Helps optimize performance by deferring computations, especially when the effect might not be needed, or when its computation is expensive. This also ensures that any side effects or scoped captures are re-executed on each invocation.
Handling Circular Dependencies: Useful in managing circular dependencies, such as recursive functions that need to avoid eager evaluation to prevent stack overflow.
Unifying Return Types: Can help TypeScript unify return types in situations where multiple branches of logic return different effects, simplifying type inference.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Creates an Effect that always succeeds with a given value.
When to Use
Use this function when you need an effect that completes successfully with a
specific value without any errors or external dependencies.
@see ― fail to create an effect that represents a failure.
@example
// Title: Creating a Successful Effect
import { Effect } from"effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
constsuccess= Effect.succeed(42)
@since ― 2.0.0
succeed(
a: number
a/
b: number
b)
26
)
Cheatsheet
The table provides a summary of the available constructors, along with their input and output types, allowing you to choose the appropriate function based on your needs.