# Table of Contents
- [Introduction | Effect Documentation](#introduction-effect-documentation)
- [Introduction | Effect Documentation](#introduction-effect-documentation)
- [Introduction | Effect Documentation](#introduction-effect-documentation)
- [Installation | Effect Documentation](#installation-effect-documentation)
- [Why Effect? | Effect Documentation](#why-effect-effect-documentation)
- [Create Effect App | Effect Documentation](#create-effect-app-effect-documentation)
- [Importing Effect | Effect Documentation](#importing-effect-effect-documentation)
- [The Effect Type | Effect Documentation](#the-effect-type-effect-documentation)
- [Creating Effects | Effect Documentation](#creating-effects-effect-documentation)
- [Running Effects | Effect Documentation](#running-effects-effect-documentation)
- [Two Types of Errors | Effect Documentation](#two-types-of-errors-effect-documentation)
- [Unexpected Errors | Effect Documentation](#unexpected-errors-effect-documentation)
- [Using Generators | Effect Documentation](#using-generators-effect-documentation)
---
# Introduction | Effect Documentation
Introduction
============
Welcome to the Effect documentation!
Effect is a powerful TypeScript library designed to help developers easily create complex, synchronous, and asynchronous programs.
Some of the main Effect features include:
| Feature | Description |
| --- | --- |
| **Concurrency** | Achieve highly-scalable, ultra low-latency applications through Effect’s fiber-based concurrency model. |
| **Composability** | Construct highly maintainable, readable, and flexible software through the use of small, reusable building blocks. |
| **Resource Safety** | Safely manage acquisition and release of resources, even when your program fails. |
| **Type Safety** | Leverage the TypeScript type system to the fullest with Effect’s focus on type inference and type safety. |
| **Error Handling** | Handle errors in a structured and reliable manner using Effect’s built-in error handling capabilities. |
| **Asynchronicity** | Write code that looks the same, whether it is synchronous or asynchronous. |
| **Observability** | With full tracing capabilities, you can easily debug and monitor the execution of your Effect program. |
How to Use These Docs
---------------------
[](#how-to-use-these-docs)
The documentation is structured in a sequential manner, starting from the basics and progressing to more advanced topics. This allows you to follow along step-by-step as you build your Effect application. However, you have the flexibility to read the documentation in any order or jump directly to the pages that are relevant to your specific use case.
To facilitate navigation within a page, you will find a table of contents on the right side of the screen. This allows you to easily jump between different sections of the page.
### Docs for LLMs
[](#docs-for-llms)
We support the [llms.txt](https://llmstxt.org/)
convention for making documentation available to large language models and the applications that make use of them.
Currently, we have the following root-level files:
* [/llms.txt](https://effect.website/llms.txt)
— a listing of the available files
* [/llms-full.txt](https://effect.website/llms-full.txt)
— complete documentation for Effect
* [/llms-small.txt](https://effect.website/llms-small.txt)
— compressed documentation for use with smaller context windows
Join our Community
------------------
[](#join-our-community)
If you have questions about anything related to Effect, you’re always welcome to ask our community on [Discord](https://discord.gg/effect-ts)
.
---
# Introduction | Effect Documentation
Introduction
============
Welcome to the Effect documentation!
Effect is a powerful TypeScript library designed to help developers easily create complex, synchronous, and asynchronous programs.
Some of the main Effect features include:
| Feature | Description |
| --- | --- |
| **Concurrency** | Achieve highly-scalable, ultra low-latency applications through Effect’s fiber-based concurrency model. |
| **Composability** | Construct highly maintainable, readable, and flexible software through the use of small, reusable building blocks. |
| **Resource Safety** | Safely manage acquisition and release of resources, even when your program fails. |
| **Type Safety** | Leverage the TypeScript type system to the fullest with Effect’s focus on type inference and type safety. |
| **Error Handling** | Handle errors in a structured and reliable manner using Effect’s built-in error handling capabilities. |
| **Asynchronicity** | Write code that looks the same, whether it is synchronous or asynchronous. |
| **Observability** | With full tracing capabilities, you can easily debug and monitor the execution of your Effect program. |
How to Use These Docs
---------------------
[](#how-to-use-these-docs)
The documentation is structured in a sequential manner, starting from the basics and progressing to more advanced topics. This allows you to follow along step-by-step as you build your Effect application. However, you have the flexibility to read the documentation in any order or jump directly to the pages that are relevant to your specific use case.
To facilitate navigation within a page, you will find a table of contents on the right side of the screen. This allows you to easily jump between different sections of the page.
### Docs for LLMs
[](#docs-for-llms)
We support the [llms.txt](https://llmstxt.org/)
convention for making documentation available to large language models and the applications that make use of them.
Currently, we have the following root-level files:
* [/llms.txt](https://effect.website/llms.txt)
— a listing of the available files
* [/llms-full.txt](https://effect.website/llms-full.txt)
— complete documentation for Effect
* [/llms-small.txt](https://effect.website/llms-small.txt)
— compressed documentation for use with smaller context windows
Join our Community
------------------
[](#join-our-community)
If you have questions about anything related to Effect, you’re always welcome to ask our community on [Discord](https://discord.gg/effect-ts)
.
---
# Introduction | Effect Documentation
Introduction
============
Welcome to the Effect documentation!
Effect is a powerful TypeScript library designed to help developers easily create complex, synchronous, and asynchronous programs.
Some of the main Effect features include:
| Feature | Description |
| --- | --- |
| **Concurrency** | Achieve highly-scalable, ultra low-latency applications through Effect’s fiber-based concurrency model. |
| **Composability** | Construct highly maintainable, readable, and flexible software through the use of small, reusable building blocks. |
| **Resource Safety** | Safely manage acquisition and release of resources, even when your program fails. |
| **Type Safety** | Leverage the TypeScript type system to the fullest with Effect’s focus on type inference and type safety. |
| **Error Handling** | Handle errors in a structured and reliable manner using Effect’s built-in error handling capabilities. |
| **Asynchronicity** | Write code that looks the same, whether it is synchronous or asynchronous. |
| **Observability** | With full tracing capabilities, you can easily debug and monitor the execution of your Effect program. |
How to Use These Docs
---------------------
[](#how-to-use-these-docs)
The documentation is structured in a sequential manner, starting from the basics and progressing to more advanced topics. This allows you to follow along step-by-step as you build your Effect application. However, you have the flexibility to read the documentation in any order or jump directly to the pages that are relevant to your specific use case.
To facilitate navigation within a page, you will find a table of contents on the right side of the screen. This allows you to easily jump between different sections of the page.
### Docs for LLMs
[](#docs-for-llms)
We support the [llms.txt](https://llmstxt.org/)
convention for making documentation available to large language models and the applications that make use of them.
Currently, we have the following root-level files:
* [/llms.txt](https://effect.website/llms.txt)
— a listing of the available files
* [/llms-full.txt](https://effect.website/llms-full.txt)
— complete documentation for Effect
* [/llms-small.txt](https://effect.website/llms-small.txt)
— compressed documentation for use with smaller context windows
Join our Community
------------------
[](#join-our-community)
If you have questions about anything related to Effect, you’re always welcome to ask our community on [Discord](https://discord.gg/effect-ts)
.
---
# Installation | Effect Documentation
Installation
============
Requirements:
* TypeScript 5.4 or newer.
* Node.js, Deno, and Bun are supported.
Automatic Installation
----------------------
[](#automatic-installation)
To quickly set up a new Effect application, we recommend using `create-effect-app`, which will handle all configurations for you. To create a new project, run:
* [npm](#tab-panel-44)
* [pnpm](#tab-panel-45)
* [Yarn](#tab-panel-46)
* [Bun](#tab-panel-47)
* [Deno](#tab-panel-48)
npx create-effect-app@latest
pnpm create effect-app@latest
yarn create effect-app@latest
bunx create-effect-app@latest
deno init --npm effect-app@latest
Once you complete the prompts, `create-effect-app` will create a folder with your project name and install all required dependencies.
For more details on the CLI, see the [Create Effect App](/docs/getting-started/create-effect-app/)
documentation.
Manual Installation
-------------------
[](#manual-installation)
### Node.js
[](#nodejs)
Follow these steps to create a new Effect project for [Node.js](https://nodejs.org/)
:
1. Create a project directory and navigate into it:
mkdir hello-effectcd hello-effect
2. Initialize a TypeScript project:
* [npm](#tab-panel-49)
* [pnpm](#tab-panel-50)
* [Yarn](#tab-panel-51)
npm init -ynpm install --save-dev typescript
pnpm initpnpm add --save-dev typescript
yarn init -yyarn add --dev typescript
This creates a `package.json` file with an initial setup for your TypeScript project.
3. Initialize TypeScript:
* [npm](#tab-panel-52)
* [pnpm](#tab-panel-53)
* [Yarn](#tab-panel-54)
npm tsc --init
pnpm tsc --init
yarn tsc --init
When running this command, it will generate a `tsconfig.json` file that contains configuration options for TypeScript. One of the most important options to consider is the `strict` flag.
Make sure to open the `tsconfig.json` file and verify that the value of the `strict` option is set to `true`.
{ "compilerOptions": { "strict": true }}
4. Install the necessary package as dependency:
* [npm](#tab-panel-55)
* [pnpm](#tab-panel-56)
* [Yarn](#tab-panel-57)
npm install effect
pnpm add effect
yarn add effect
This package will provide the foundational functionality for your Effect project.
Let’s write and run a simple program to ensure that everything is set up correctly.
In your terminal, execute the following commands:
mkdir srctouch src/index.ts
Open the `index.ts` file and add the following code:
1import { Effect, Console } from "effect"2
3const program = Console.log("Hello, World!")4
5Effect.runSync(program)
Run the `index.ts` file. Here we are using [tsx](https://github.com/privatenumber/tsx)
to run the `index.ts` file in the terminal:
npx tsx src/index.ts
You should see the message `"Hello, World!"` printed. This confirms that the program is working correctly.
### Deno
[](#deno)
Follow these steps to create a new Effect project for [Deno](https://deno.com/)
:
1. Create a project directory and navigate into it:
mkdir hello-effectcd hello-effect
2. Initialize Deno:
deno init
3. Install the necessary package as dependency:
deno add npm:effect
This package will provide the foundational functionality for your Effect project.
Let’s write and run a simple program to ensure that everything is set up correctly.
Open the `main.ts` file and replace the content with the following code:
1import { Effect, Console } from "effect"2
3const program = Console.log("Hello, World!")4
5Effect.runSync(program)
Run the `main.ts` file:
deno run main.ts
You should see the message `"Hello, World!"` printed. This confirms that the program is working correctly.
### Bun
[](#bun)
Follow these steps to create a new Effect project for [Bun](https://bun.sh/)
:
1. Create a project directory and navigate into it:
mkdir hello-effectcd hello-effect
2. Initialize Bun:
bun init
When running this command, it will generate a `tsconfig.json` file that contains configuration options for TypeScript. One of the most important options to consider is the `strict` flag.
Make sure to open the `tsconfig.json` file and verify that the value of the `strict` option is set to `true`.
{ "compilerOptions": { "strict": true }}
3. Install the necessary package as dependency:
bun add effect
This package will provide the foundational functionality for your Effect project.
Let’s write and run a simple program to ensure that everything is set up correctly.
Open the `index.ts` file and replace the content with the following code:
1import { Effect, Console } from "effect"2
3const program = Console.log("Hello, World!")4
5Effect.runSync(program)
Run the `index.ts` file:
bun index.ts
You should see the message `"Hello, World!"` printed. This confirms that the program is working correctly.
### Vite + React
[](#vite--react)
Follow these steps to create a new Effect project for [Vite](https://vitejs.dev/guide/)
+ [React](https://react.dev/)
:
1. Scaffold your Vite project, open your terminal and run the following command:
* [npm](#tab-panel-58)
* [pnpm](#tab-panel-59)
* [Yarn](#tab-panel-60)
* [Bun](#tab-panel-61)
* [Deno](#tab-panel-62)
# npm 6.xnpm create vite@latest hello-effect --template react-ts# npm 7+, extra double-dash is needednpm create vite@latest hello-effect -- --template react-ts
pnpm create vite@latest hello-effect -- --template react-ts
yarn create vite@latest hello-effect -- --template react-ts
bun create vite@latest hello-effect -- --template react-ts
deno init --npm vite@latest hello-effect -- --template react-ts
This command will create a new Vite project with React and TypeScript template.
2. Navigate into the newly created project directory and install the required packages:
* [npm](#tab-panel-63)
* [pnpm](#tab-panel-64)
* [Yarn](#tab-panel-65)
* [Bun](#tab-panel-66)
* [Deno](#tab-panel-67)
cd hello-effectnpm install
cd hello-effectpnpm install
cd hello-effectyarn install
cd hello-effectbun install
cd hello-effectdeno install
Once the packages are installed, open the `tsconfig.json` file and ensure that the value of the `strict` option is set to true.
{ "compilerOptions": { "strict": true }}
3. Install the necessary package as dependency:
* [npm](#tab-panel-68)
* [pnpm](#tab-panel-69)
* [Yarn](#tab-panel-70)
* [Bun](#tab-panel-71)
* [Deno](#tab-panel-72)
npm install effect
pnpm add effect
yarn add effect
bun add effect
deno add effect
This package will provide the foundational functionality for your Effect project.
Now, let’s write and run a simple program to ensure that everything is set up correctly.
Open the `src/App.tsx` file and replace its content with the following code:
1import { useState, useMemo, useCallback } from "react"2import reactLogo from "./assets/react.svg"3import viteLogo from "/vite.svg"4import "./App.css"5import { Effect } from "effect"6
7function App() {8 const [count, setCount] = useState(0)9
10 const task = useMemo(11 () => Effect.sync(() => setCount((current) => current + 1)),12 [setCount]13 )14
15 const increment = useCallback(() => Effect.runSync(task), [task])16
17 return (18 <>19
35 Click on the Vite and React logos to learn more36
37 >38 )39}40
41export default App
After making these changes, start the development server by running the following command:
* [npm](#tab-panel-73)
* [pnpm](#tab-panel-74)
* [Yarn](#tab-panel-75)
* [Bun](#tab-panel-76)
* [Deno](#tab-panel-77)
npm run dev
pnpm run dev
yarn run dev
bun run dev
deno run dev
Then, press **o** to open the application in your browser.
When you click the button, you should see the counter increment. This confirms that the program is working correctly.
---
# Why Effect? | Effect Documentation
Why Effect?
===========
Programming is challenging. When we build libraries and apps, we look to many tools to handle the complexity and make our day-to-day more manageable. Effect presents a new way of thinking about programming in TypeScript.
Effect is an ecosystem of tools that help you build better applications and libraries. As a result, you will also learn more about the TypeScript language and how to use the type system to make your programs more reliable and easier to maintain.
In “typical” TypeScript, without Effect, we write code that assumes that a function is either successful or throws an exception. For example:
1const const divide: (a: number, b: number) => numberdivide = (a: numbera: number, b: numberb: number): number => {2 if (b: numberb === 0) {3 throw new var Error: ErrorConstructornew (message?: string) => ErrorError("Cannot divide by zero")4 }5 return a: numbera / b: numberb6}
Based on the types, we have no idea that this function can throw an exception. We can only find out by reading the code. This may not seem like much of a problem when you only have one function in your codebase, but when you have hundreds or thousands, it really starts to add up. It’s easy to forget that a function can throw an exception, and it’s easy to forget to handle that exception.
Often, we will do the “easiest” thing and just wrap the function in a `try/catch` block. This is a good first step to prevent your program from crashing, but it doesn’t make it any easier to manage or understand our complex application/library. We can do better.
One of the most important tools we have in TypeScript is the compiler. It is the first line of defense against bugs, domain errors, and general complexity.
The Effect Pattern
------------------
[](#the-effect-pattern)
While Effect is a vast ecosystem of many different tools, if it had to be reduced down to just one idea, it would be the following:
Effect’s major unique insight is that we can use the type system to track **errors** and **context**, not only **success** values as shown in the divide example above.
Here’s the same divide function from above, but with the Effect pattern:
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const divide: (a: number, b: number) => Effect.Effectdivide = (4 a: numbera: number,5 b: numberb: number6): import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.interface EffectThe Effect interface defines a value that describes a workflow or job,
which can succeed or fail.
Details
The Effect interface represents a computation that can model a workflow
involving various types of operations, such as synchronous, asynchronous,
concurrent, and parallel interactions. It operates within a context of type
R, and the result can either be a success with a value of type A or a
failure with an error of type E. The Effect is designed to handle complex
interactions with external resources, offering advanced features such as
fiber-based concurrency, scheduling, interruption handling, and scalability.
This makes it suitable for tasks that require fine-grained control over
concurrency and error management.
To execute an Effect value, you need a Runtime, which provides the
environment necessary to run and manage the computation.@since ― 2.0.0@since ― 2.0.0Effect =>7 b: numberb === 08 ? import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fail: (error: Error) => Effect.EffectCreates 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
.
Example (Creating a Failed Effect)
import { Effect } from "effect"
// ┌─── Effect// ▼const failure = Effect.fail( new Error("Operation failed due to network error"))@see ― succeed to create an effect that represents a successful value.@since ― 2.0.0fail(new var Error: ErrorConstructornew (message?: string) => ErrorError("Cannot divide by zero"))9 : import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const succeed: (value: number) => Effect.EffectCreates 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.
Example (Creating a Successful Effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario//// ┌─── Effect// ▼const success = Effect.succeed(42)@see ― fail to create an effect that represents a failure.@since ― 2.0.0succeed(a: numbera / b: numberb)
With this approach, the function no longer throws exceptions. Instead, errors are handled as values, which can be passed along like success values. The type signature also makes it clear:
* What success value the function returns (`number`).
* What error can occur (`Error`).
* What additional context or dependencies are required (`never` indicates none).
┌─── Produces a value of type number │ ┌─── Fails with an Error │ │ ┌─── Requires no dependencies ▼ ▼ ▼Effect
Additionally, tracking context allows you to provide additional information to your functions without having to pass in everything as an argument. For example, you can swap out implementations of live external services with mocks during your tests without changing any core business logic.
Don’t Re-Invent the Wheel
-------------------------
[](#dont-re-invent-the-wheel)
Application code in TypeScript often solves the same problems over and over again. Interacting with external services, filesystems, databases, etc. are common problems for all application developers. Effect provides a rich ecosystem of libraries that provide standardized solutions to many of these problems. You can use these libraries to build your application, or you can use them to build your own libraries.
Managing challenges like error handling, debugging, tracing, async/promises, retries, streaming, concurrency, caching, resource management, and a lot more are made manageable with Effect. You don’t have to re-invent the solutions to these problems, or install tons of dependencies. Effect, under one umbrella, solves many of the problems that you would usually install many different dependencies with different APIs to solve.
Solving Practical Problems
--------------------------
[](#solving-practical-problems)
Effect is heavily inspired by great work done in other languages, like Scala and Haskell. However, it’s important to understand that Effect’s goal is to be a practical toolkit, and it goes to great lengths to solve real, everyday problems that developers face when building applications and libraries in TypeScript.
Enjoy Building and Learning
---------------------------
[](#enjoy-building-and-learning)
Learning Effect is a lot of fun. Many developers in the Effect ecosystem are using Effect to solve real problems in their day-to-day work, and also experiment with cutting edge ideas for pushing TypeScript to be the most useful language it can be.
You don’t have to use all aspects of Effect at once, and can start with the pieces of the ecosystem that make the most sense for the problems you are solving. Effect is a toolkit, and you can pick and choose the pieces that make the most sense for your use case. However, as more and more of your codebase is using Effect, you will probably find yourself wanting to utilize more of the ecosystem!
Effect’s concepts may be new to you, and might not completely make sense at first. This is totally normal. Take your time with reading the docs and try to understand the core concepts - this will really pay off later on as you get into the more advanced tooling in the Effect ecosystem. The Effect community is always happy to help you learn and grow. Feel free to hop into our [Discord](https://discord.gg/effect-ts)
or discuss on [GitHub](https://github.com/Effect-TS)
! We are open to feedback and contributions, and are always looking for ways to improve Effect.
---
# Create Effect App | Effect Documentation
Create Effect App
=================
The `create-effect-app` CLI allow you to create a new Effect application using a default template or an [example](https://github.com/Effect-TS/examples)
from a public Github repository. It is the easiest way to get started with Effect.
CLI
---
[](#cli)
To begin, run the `create-effect-app` command in your terminal using your preferred package manager:
* [npm](#tab-panel-34)
* [pnpm](#tab-panel-35)
* [Yarn](#tab-panel-36)
* [Bun](#tab-panel-37)
* [Deno](#tab-panel-38)
npx create-effect-app@latest
pnpm create effect-app@latest
yarn create effect-app@latest
bunx create-effect-app@latest
deno init --npm effect-app@latest
This command starts an interactive setup that guides you through the steps required to bootstrap your project:

After making your selections, `create-effect-app` will generate your new Effect project and configure it based on your choices.
**Example**
For instance, to create a new Effect project in a directory named `"my-effect-app"` using the basic template with ESLint integration, you can run:
npx create-effect-app --template basic --eslint my-effect-app
Non-Interactive Usage
---------------------
[](#non-interactive-usage)
If you prefer, `create-effect-app` can also be used in a non-interactive mode:
create-effect-app (-t, --template basic | cli | monorepo) [--changesets] [--flake] [--eslint] [--workflows] []create-effect-app (-e, --example http-server) []
Below is a breakdown of the available options to customize an Effect project template:
| Option | Description |
| --- | --- |
| `--changesets` | Initializes your project with the Changesets package for managing version control. |
| `--flake` | Initializes your project with a Nix flake for managing system dependencies. |
| `--eslint` | Includes ESLint for code formatting and linting. |
| `--workflows` | Sets up Effect’s recommended GitHub Action workflows for automation. |
---
# Importing Effect | Effect Documentation
Importing Effect
================
If you’re just getting started, you might feel overwhelmed by the variety of modules and functions that Effect offers.
However, rest assured that you don’t need to worry about all of them right away.
This page will provide a simple introduction on how to import modules and functions, and explain that installing the `effect` package is generally all you need to begin.
Installing Effect
-----------------
[](#installing-effect)
If you haven’t already installed the `effect` package, you can do so by running the following command in your terminal:
* [npm](#tab-panel-39)
* [pnpm](#tab-panel-40)
* [Yarn](#tab-panel-41)
* [Bun](#tab-panel-42)
* [Deno](#tab-panel-43)
npm install effect
pnpm add effect
yarn add effect
bun add effect
deno add npm:effect
By installing this package, you get access to the core functionality of Effect.
For detailed installation instructions for platforms like Deno or Bun, refer to the [Installation](/docs/getting-started/installation/)
guide, which provides step-by-step guidance.
You can also start a new Effect app using [`create-effect-app`](/docs/getting-started/create-effect-app/)
, which automatically sets up everything for you.
Importing Modules and Functions
-------------------------------
[](#importing-modules-and-functions)
Once you have installed the `effect` package, you can start using its modules and functions in your projects. Importing modules and functions is straightforward and follows the standard JavaScript/TypeScript import syntax.
To import a module or a function from the `effect` package, simply use the `import` statement at the top of your file. Here’s how you can import the `Effect` module:
import { Effect } from "effect"
Now, you have access to the Effect module, which is the heart of the Effect library. It provides various functions to create, compose, and manipulate effectful computations.
Namespace imports
-----------------
[](#namespace-imports)
In addition to importing the `Effect` module with a named import, as shown previously:
import { Effect } from "effect"
You can also import it using a namespace import like this:
import * as Effect from "effect/Effect"
Both forms of import allow you to access the functionalities provided by the `Effect` module.
However an important consideration is **tree shaking**, which refers to a process that eliminates unused code during the bundling of your application. Named imports may generate tree shaking issues when a bundler doesn’t support deep scope analysis.
Here are some bundlers that support deep scope analysis and thus don’t have issues with named imports:
* Rollup
* Webpack 5+
Functions vs Methods
--------------------
[](#functions-vs-methods)
In the Effect ecosystem, libraries often expose functions rather than methods. This design choice is important for two key reasons: tree shakeability and extendibility.
### Tree Shakeability
[](#tree-shakeability)
Tree shakeability refers to the ability of a build system to eliminate unused code during the bundling process. Functions are tree shakeable, while methods are not.
When functions are used in the Effect ecosystem, only the functions that are actually imported and used in your application will be included in the final bundled code. Unused functions are automatically removed, resulting in a smaller bundle size and improved performance.
On the other hand, methods are attached to objects or prototypes, and they cannot be easily tree shaken. Even if you only use a subset of methods, all methods associated with an object or prototype will be included in the bundle, leading to unnecessary code bloat.
### Extendibility
[](#extendibility)
Another important advantage of using functions in the Effect ecosystem is the ease of extendibility. With methods, extending the functionality of an existing API often requires modifying the prototype of the object, which can be complex and error-prone.
In contrast, with functions, extending the functionality is much simpler. You can define your own “extension methods” as plain old functions without the need to modify the prototypes of objects. This promotes cleaner and more modular code, and it also allows for better compatibility with other libraries and modules.
Commonly Used Functions
-----------------------
[](#commonly-used-functions)
As you start your adventure with Effect, you don’t need to dive into every function in the `effect` package right away. Instead, focus on some commonly used functions that will provide a solid foundation for your journey into the world of Effect.
In the upcoming guides, we will explore some of these essential functions, specifically those for creating and running `Effect`s and building pipelines.
But before we dive into those, let’s start from the very heart of Effect: understanding the `Effect` type. This will lay the groundwork for your understanding of how Effect brings composability, type safety, and error handling into your applications.
So, let’s take the first step and explore the fundamental concepts of the [The Effect Type](/docs/getting-started/the-effect-type/)
.
---
# The Effect Type | Effect Documentation
The Effect Type
===============
The `Effect` type is an **immutable** description of a workflow or operation that is **lazily** executed. This means that when you create an `Effect`, it doesn’t run immediately, but instead defines a program that can succeed, fail, or require some additional context to complete.
Here is the general form of an `Effect`:
┌─── Represents the success type │ ┌─── Represents the error type │ │ ┌─── Represents required dependencies ▼ ▼ ▼Effect
This type indicates that an effect:
* Succeeds and returns a value of type `Success`
* Fails with an error of type `Error`
* May need certain contextual dependencies of type `Requirements` to execute
Conceptually, you can think of `Effect` as an effectful version of the following function type:
type Effect = ( context: Context) => Error | Success
However, effects are not actually functions. They can model synchronous, asynchronous, concurrent, and resourceful computations.
**Immutability**. `Effect` values are immutable, and every function in the Effect library produces a new `Effect` value.
**Modeling Interactions**. These values do not perform any actions themselves, they simply model or describe effectful interactions.
**Execution**. An `Effect` can be executed by the [Effect Runtime System](/docs/runtime/)
, which interprets it into actual interactions with the external world. Ideally, this execution happens at a single entry point in your application, such as the main function where effectful operations are initiated.
Type Parameters
---------------
[](#type-parameters)
The `Effect` type has three type parameters with the following meanings:
| Parameter | Description |
| --- | --- |
| **Success** | Represents the type of value that an effect can succeed with when executed. If this type parameter is `void`, it means the effect produces no useful information, while if it is `never`, it means the effect runs forever (or until failure). |
| **Error** | Represents the expected errors that can occur when executing an effect. If this type parameter is `never`, it means the effect cannot fail, because there are no values of type `never`. |
| **Requirements** | Represents the contextual data required by the effect to be executed. This data is stored in a collection named `Context`. If this type parameter is `never`, it means the effect has no requirements and the `Context` collection is empty. |
Extracting Inferred Types
-------------------------
[](#extracting-inferred-types)
By using the utility types `Effect.Success`, `Effect.Error`, and `Effect.Context`, you can extract the corresponding types from an effect.
**Example** (Extracting Success, Error, and Context Types)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect, import Context@since ― 2.0.0@since ― 2.0.0Context } from "effect"2
3class class SomeContextSomeContext extends import Context@since ― 2.0.0@since ― 2.0.0Context.const Tag: <"SomeContext">(id: "SomeContext") => () => Context.TagClass@example import * as assert from "node:assert"import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")< MyTag, { readonly myNum: number }>() { static Live = Layer.succeed(this, { myNum: 108 })}@since ― 2.0.0Tag("SomeContext")() {}4
5// Assume we have an effect that succeeds with a number,6// fails with an Error, and requires SomeContext7declare const const program: Effect.Effectprogram: import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.interface EffectThe Effect interface defines a value that describes a workflow or job,
which can succeed or fail.
Details
The Effect interface represents a computation that can model a workflow
involving various types of operations, such as synchronous, asynchronous,
concurrent, and parallel interactions. It operates within a context of type
R, and the result can either be a success with a value of type A or a
failure with an error of type E. The Effect is designed to handle complex
interactions with external resources, offering advanced features such as
fiber-based concurrency, scheduling, interruption handling, and scalability.
This makes it suitable for tasks that require fine-grained control over
concurrency and error management.
To execute an Effect value, you need a Runtime, which provides the
environment necessary to run and manage the computation.@since ― 2.0.0@since ― 2.0.0Effect8
9// Extract the success type, which is number10type type A = numberA = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.namespace EffectThe Effect interface defines a value that describes a workflow or job,
which can succeed or fail.
Details
The Effect interface represents a computation that can model a workflow
involving various types of operations, such as synchronous, asynchronous,
concurrent, and parallel interactions. It operates within a context of type
R, and the result can either be a success with a value of type A or a
failure with an error of type E. The Effect is designed to handle complex
interactions with external resources, offering advanced features such as
fiber-based concurrency, scheduling, interruption handling, and scalability.
This makes it suitable for tasks that require fine-grained control over
concurrency and error management.
To execute an Effect value, you need a Runtime, which provides the
environment necessary to run and manage the computation.@since ― 2.0.0@since ― 2.0.0Effect.type Effect.Success> = [T] extends [Effect.Effect] ? _A : never@since ― 2.0.0Successprogram>11
12// Extract the error type, which is Error13type type E = ErrorE = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.namespace EffectThe Effect interface defines a value that describes a workflow or job,
which can succeed or fail.
Details
The Effect interface represents a computation that can model a workflow
involving various types of operations, such as synchronous, asynchronous,
concurrent, and parallel interactions. It operates within a context of type
R, and the result can either be a success with a value of type A or a
failure with an error of type E. The Effect is designed to handle complex
interactions with external resources, offering advanced features such as
fiber-based concurrency, scheduling, interruption handling, and scalability.
This makes it suitable for tasks that require fine-grained control over
concurrency and error management.
To execute an Effect value, you need a Runtime, which provides the
environment necessary to run and manage the computation.@since ― 2.0.0@since ― 2.0.0Effect.type Effect.Error> = [T] extends [Effect.Effect] ? _E : never@since ― 2.0.0Errorprogram>14
15// Extract the context type, which is SomeContext16type type R = SomeContextR = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.namespace EffectThe Effect interface defines a value that describes a workflow or job,
which can succeed or fail.
Details
The Effect interface represents a computation that can model a workflow
involving various types of operations, such as synchronous, asynchronous,
concurrent, and parallel interactions. It operates within a context of type
R, and the result can either be a success with a value of type A or a
failure with an error of type E. The Effect is designed to handle complex
interactions with external resources, offering advanced features such as
fiber-based concurrency, scheduling, interruption handling, and scalability.
This makes it suitable for tasks that require fine-grained control over
concurrency and error management.
To execute an Effect value, you need a Runtime, which provides the
environment necessary to run and manage the computation.@since ― 2.0.0@since ― 2.0.0Effect.type Effect.Context> = [T] extends [Effect.Effect] ? _R : never@since ― 2.0.0Contextprogram>
---
# Creating Effects | Effect Documentation
Creating Effects
================
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?
---------------------
[](#why-not-throw-errors)
In traditional programming, when an error occurs, it is often handled by throwing an exception:
1// Type signature doesn't show possible exceptions2const const divide: (a: number, b: number) => numberdivide = (a: numbera: number, b: numberb: number): number => {3 if (b: numberb === 0) {4 throw new var Error: ErrorConstructornew (message?: string) => ErrorError("Cannot divide by zero")5 }6 return a: numbera / b: numberb7}
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
[](#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.
**Example** (Creating a Successful Effect)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3// ┌─── Effect4// ▼5const const success: Effect.Effectsuccess = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const succeed: (value: number) => Effect.EffectCreates 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.
Example (Creating a Successful Effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario//// ┌─── Effect// ▼const success = Effect.succeed(42)@see ― fail to create an effect that represents a failure.@since ― 2.0.0succeed(42)
The type of `success` is `Effect`, 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
### fail
[](#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](/docs/error-management/expected-errors/#catchall)
or [Effect.catchTag](/docs/error-management/expected-errors/#catchtag)
.
**Example** (Creating a Failed Effect)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3// ┌─── Effect4// ▼5const const failure: Effect.Effectfailure = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fail: (error: Error) => Effect.EffectCreates 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
.
Example (Creating a Failed Effect)
import { Effect } from "effect"
// ┌─── Effect// ▼const failure = Effect.fail( new Error("Operation failed due to network error"))@see ― succeed to create an effect that represents a successful value.@since ― 2.0.0fail(6 new var Error: ErrorConstructornew (message?: string) => ErrorError("Operation failed due to network error")7)
The type of `failure` is `Effect`, 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
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](/docs/error-management/expected-errors/#catchtag)
.
**Example** (Using Tagged Errors)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3class class HttpErrorHttpError {4 readonly HttpError._tag: "HttpError"_tag = "HttpError"5}6
7// ┌─── Effect8// ▼9const const program: Effect.Effectprogram = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fail: (error: HttpError) => Effect.EffectCreates 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
.
Example (Creating a Failed Effect)
import { Effect } from "effect"
// ┌─── Effect// ▼const failure = Effect.fail( new Error("Operation failed due to network error"))@see ― succeed to create an effect that represents a successful value.@since ― 2.0.0fail(new constructor HttpError(): HttpErrorHttpError())
Error Tracking
--------------
[](#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`](#why-not-throw-errors)
function using Effect, making error handling explicit.
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const divide: (a: number, b: number) => Effect.Effectdivide = (a: numbera: number, b: numberb: number): import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.interface EffectThe Effect interface defines a value that describes a workflow or job,
which can succeed or fail.
Details
The Effect interface represents a computation that can model a workflow
involving various types of operations, such as synchronous, asynchronous,
concurrent, and parallel interactions. It operates within a context of type
R, and the result can either be a success with a value of type A or a
failure with an error of type E. The Effect is designed to handle complex
interactions with external resources, offering advanced features such as
fiber-based concurrency, scheduling, interruption handling, and scalability.
This makes it suitable for tasks that require fine-grained control over
concurrency and error management.
To execute an Effect value, you need a Runtime, which provides the
environment necessary to run and manage the computation.@since ― 2.0.0@since ― 2.0.0Effect =>4 b: numberb === 05 ? import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fail: (error: Error) => Effect.EffectCreates 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
.
Example (Creating a Failed Effect)
import { Effect } from "effect"
// ┌─── Effect// ▼const failure = Effect.fail( new Error("Operation failed due to network error"))@see ― succeed to create an effect that represents a successful value.@since ― 2.0.0fail(new var Error: ErrorConstructornew (message?: string) => ErrorError("Cannot divide by zero"))6 : import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const succeed: (value: number) => Effect.EffectCreates 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.
Example (Creating a Successful Effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario//// ┌─── Effect// ▼const success = Effect.succeed(42)@see ― fail to create an effect that represents a failure.@since ― 2.0.0succeed(a: numbera / b: numberb)
In this example, the `divide` function indicates in its return type `Effect` 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
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:
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3// Define a User type4interface interface UserUser {5 readonly User.id: numberid: number6 readonly User.name: stringname: string7}8
9// A mocked function to simulate fetching a user from a database10const const getUser: (userId: number) => Effect.EffectgetUser = (userId: numberuserId: number): import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.interface EffectThe Effect interface defines a value that describes a workflow or job,
which can succeed or fail.
Details
The Effect interface represents a computation that can model a workflow
involving various types of operations, such as synchronous, asynchronous,
concurrent, and parallel interactions. It operates within a context of type
R, and the result can either be a success with a value of type A or a
failure with an error of type E. The Effect is designed to handle complex
interactions with external resources, offering advanced features such as
fiber-based concurrency, scheduling, interruption handling, and scalability.
This makes it suitable for tasks that require fine-grained control over
concurrency and error management.
To execute an Effect value, you need a Runtime, which provides the
environment necessary to run and manage the computation.@since ― 2.0.0@since ― 2.0.0Effect => {11 // Normally, you would access a database or API here, but we'll mock it12 const const userDatabase: RecorduserDatabase: type Record = { [P in K]: T; }Construct a type with a set of properties K of type TRecord = {13 1: { User.id: numberid: 1, User.name: stringname: "John Doe" },14 2: { User.id: numberid: 2, User.name: stringname: "Jane Smith" }15 }16
17 // Check if the user exists in our "database" and return appropriately18 const const user: Useruser = const userDatabase: RecorduserDatabase[userId: numberuserId]19 if (const user: Useruser) {20 return import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const succeed: (value: User) => Effect.EffectCreates 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.
Example (Creating a Successful Effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario//// ┌─── Effect// ▼const success = Effect.succeed(42)@see ― fail to create an effect that represents a failure.@since ― 2.0.0succeed(const user: Useruser)21 } else {22 return import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fail: (error: Error) => Effect.EffectCreates 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
.
Example (Creating a Failed Effect)
import { Effect } from "effect"
// ┌─── Effect// ▼const failure = Effect.fail( new Error("Operation failed due to network error"))@see ― succeed to create an effect that represents a successful value.@since ― 2.0.0fail(new var Error: ErrorConstructornew (message?: string) => ErrorError("User not found"))23 }24}25
26// When executed, this will successfully return the user with id 127const const exampleUserEffect: Effect.EffectexampleUserEffect = const getUser: (userId: number) => Effect.EffectgetUser(1)
In this example, `exampleUserEffect`, which has the type `Effect`, 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](/docs/error-management/expected-errors/)
.
Modeling Synchronous Effects
----------------------------
[](#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
[](#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”](/docs/error-management/unexpected-errors/)
.
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](/docs/error-management/unexpected-errors/#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.
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const log: (message: string) => Effect.Effectlog = (message: stringmessage: string) =>4 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const sync: (thunk: LazyArg) => Effect.EffectCreates an Effect that represents a synchronous side-effectful computation.
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
.
When to Use
Use this function when you are sure the operation will not fail.
Example (Logging a Message)
import { Effect } from "effect"
const log = (message: string) => Effect.sync(() => { console.log(message) // side effect })
// ┌─── Effect// ▼const program = log("Hello, World!")@see ― try_try for a version that can handle failures.@since ― 2.0.0sync(() => {5 var console: ConsoleThe 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 stdoutconsole.log('hello %s', 'world');// Prints: hello world, to stdoutconsole.error(new Error('Whoops, something bad happened'));// Prints error message and stack trace to stderr:// Error: Whoops, something bad happened// at [eval]:5:15// at Script.runInThisContext (node:vm:132:18)// at Object.runInThisContext (node:vm:309:38)// at node:internal/process/execution:77:19// at [eval]-wrapper:6:22// at evalScript (node:internal/process/execution:76:60)// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';console.warn(`Danger ${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out = getStreamSomehow();const err = getStreamSomehow();const myConsole = new console.Console(out, err);
myConsole.log('hello world');// Prints: hello world, to outmyConsole.log('hello %s', 'world');// Prints: hello world, to outmyConsole.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@see ― sourceconsole.Console.log(message?: any, ...optionalParams: any[]): voidPrints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const count = 5;console.log('count: %d', count);// Prints: count: 5, to stdoutconsole.log('count:', count);// Prints: count: 5, to stdout
See util.format() for more information.@since ― v0.1.100log(message: stringmessage) // side effect6 })7
8// ┌─── Effect9// ▼10const const program: Effect.Effectprogram = const log: (message: string) => Effect.Effectlog("Hello, World!")
The side effect (logging to the console) encapsulated within `program` won’t occur until the effect is explicitly run (see the [Running Effects](/docs/getting-started/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
[](#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:
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const parse: (input: string) => Effect.Effectparse = (input: stringinput: string) =>4 // This might throw an error if input is not valid JSON5 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.try(thunk: LazyArg): Effect.Effect (+1 overload)export trytry(() => var JSON: JSONAn 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): anyConverts 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(input: stringinput))6
7// ┌─── Effect8// ▼9const const program: Effect.Effectprogram = const parse: (input: string) => Effect.Effectparse("")
In this example:
* `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
[](#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:
**Example** (Custom Error Handling)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const parse: (input: string) => Effect.Effectparse = (input: stringinput: string) =>4 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.try(options: { readonly try: LazyArg; readonly catch: (error: unknown) => Error;}): Effect.Effect (+1 overload)export trytry({5 // JSON.parse may throw for bad input6 try: LazyArgtry: () => var JSON: JSONAn 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): anyConverts 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(input: stringinput),7 // remap the error8 catch: (error: unknown) => Errorcatch: (unknown: unknownunknown) => new var Error: ErrorConstructornew (message?: string) => ErrorError(`something went wrong ${unknown: unknownunknown}`)9 })10
11// ┌─── Effect12// ▼13const const program: Effect.Effectprogram = const parse: (input: string) => Effect.Effectparse("")
You can think of this as a similar pattern to the traditional try-catch block in JavaScript:
try { return JSON.parse(input)} catch (unknown) { throw new Error(`something went wrong ${unknown}`)}
Modeling Asynchronous Effects
-----------------------------
[](#modeling-asynchronous-effects)
In traditional programming, we often use `Promise`s to handle asynchronous computations. However, dealing with errors in promises can be problematic. By default, `Promise` 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
[](#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”](/docs/error-management/unexpected-errors/)
.
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](/docs/error-management/unexpected-errors/#catchalldefect)
. This feature ensures that even unexpected failures in your application are not lost and can be handled appropriately.
**Example** (Delayed Message)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const delay: (message: string) => Effect.Effectdelay = (message: stringmessage: string) =>4 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const promise: (evaluate: (signal: AbortSignal) => PromiseLike) => Effect.EffectCreates an Effect that represents an asynchronous computation guaranteed to
succeed.
Details
The provided function (thunk) returns a Promise that should never reject; if it does, the error
will be treated as a "defect".
This defect is not a standard error but indicates a flaw in the logic that
was expected to be error-free. You can think of it similar to an unexpected
crash in the program, which can be further managed or logged using tools like
catchAllDefect
.
Interruptions
An optional AbortSignal can be provided to allow for interruption of the
wrapped Promise API.
When to Use
Use this function when you are sure the operation will not reject.
Example (Delayed Message)
import { Effect } from "effect"
const delay = (message: string) => Effect.promise( () => new Promise((resolve) => { setTimeout(() => { resolve(message) }, 2000) }) )
// ┌─── Effect// ▼const program = delay("Async operation completed successfully!")@see ― tryPromise for a version that can handle failures.@since ― 2.0.0promise(5 () =>6 new var Promise: PromiseConstructornew (executor: (resolve: (value: string | PromiseLike) => void, reject: (reason?: any) => void) => void) => PromiseCreates 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.Promise((resolve: (value: string | PromiseLike) => voidresolve) => {7 function setTimeout<[]>(callback: () => void, ms?: number): NodeJS.Timeout (+1 overload)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(() => {8 resolve: (value: string | PromiseLike) => voidresolve(message: stringmessage)9 }, 2000)10 })11 )12
13// ┌─── Effect14// ▼15const const program: Effect.Effectprogram = const delay: (message: string) => Effect.Effectdelay("Async operation completed successfully!")
The `program` value has the type `Effect` 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
[](#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 an `UnknownException`.
**Example** (Fetching a TODO Item)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const getTodo: (id: number) => Effect.EffectgetTodo = (id: numberid: number) =>4 // Will catch any errors and propagate them as UnknownException5 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const tryPromise: (evaluate: (signal: AbortSignal) => PromiseLike) => Effect.Effect (+1 overload)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.
Example (Fetching a TODO Item)
import { Effect } from "effect"
const getTodo = (id: number) => // Will catch any errors and propagate them as UnknownException Effect.tryPromise(() => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`) )
// ┌─── Effect// ▼const program = getTodo(1)
Example (Custom Error Handling)
import { Effect } from "effect"
const getTodo = (id: number) => Effect.tryPromise({ try: () => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`), // remap the error catch: (unknown) => new Error(`something went wrong ${unknown}`) })
// ┌─── Effect// ▼const program = getTodo(1)@see ― promise if the effectful computation is asynchronous and does not throw errors.@since ― 2.0.0tryPromise(() =>6 function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promisefetch(`https://jsonplaceholder.typicode.com/todos/${id: numberid}`)7 )8
9// ┌─── Effect10// ▼11const const program: Effect.Effectprogram = const getTodo: (id: number) => Effect.EffectgetTodo(1)
The `program` value has the type `Effect` and can be interpreted as an effect that:
* succeeds with a value of type `Response`
* might produce an error (`UnknownException`)
* does not require any context (`never`)
#### Customizing Error Handling
[](#customizing-error-handling-1)
If you want more control over what gets propagated to the error channel, you can use an overload of `Effect.tryPromise` that takes a remapping function:
**Example** (Custom Error Handling)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const getTodo: (id: number) => Effect.EffectgetTodo = (id: numberid: number) =>4 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const tryPromise: (options: { readonly try: (signal: AbortSignal) => PromiseLike; readonly catch: (error: unknown) => Error;}) => Effect.Effect<...> (+1 overload)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.
Example (Fetching a TODO Item)
import { Effect } from "effect"
const getTodo = (id: number) => // Will catch any errors and propagate them as UnknownException Effect.tryPromise(() => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`) )
// ┌─── Effect// ▼const program = getTodo(1)
Example (Custom Error Handling)
import { Effect } from "effect"
const getTodo = (id: number) => Effect.tryPromise({ try: () => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`), // remap the error catch: (unknown) => new Error(`something went wrong ${unknown}`) })
// ┌─── Effect// ▼const program = getTodo(1)@see ― promise if the effectful computation is asynchronous and does not throw errors.@since ― 2.0.0tryPromise({5 try: (signal: AbortSignal) => PromiseLiketry: () => function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promisefetch(`https://jsonplaceholder.typicode.com/todos/${id: numberid}`),6 // remap the error7 catch: (error: unknown) => Errorcatch: (unknown: unknownunknown) => new var Error: ErrorConstructornew (message?: string) => ErrorError(`something went wrong ${unknown: unknownunknown}`)8 })9
10// ┌─── Effect11// ▼12const const program: Effect.Effectprogram = const getTodo: (id: number) => Effect.EffectgetTodo(1)
From a Callback
---------------
[](#from-a-callback)
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):
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2import * as module "node:fs"NodeFS from "node:fs"3
4const const readFile: (filename: string) => Effect.Effect, Error, never>readFile = (filename: stringfilename: string) =>5 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const async: , Error, never>(resume: (callback: (_: Effect.Effect, Error, never>) => void, signal: AbortSignal) => void | Effect.Effect<...>, blockingOn?: FiberId) => Effect.Effect<...>Creates an Effect from a callback-based asynchronous function.
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.
When to Use
Use Effect.async when dealing with APIs that use callback-style instead of
async/await or Promise.
Example (Wrapping a Callback API)
import { Effect } from "effect"import * as NodeFS from "node:fs"
const readFile = (filename: string) => Effect.async((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// ▼const program = readFile("example.txt")
Example (Handling Interruption with Cleanup)
import { Effect, Fiber } from "effect"import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a fileconst writeFileWithCleanup = (filename: string, data: string) => Effect.async((resume) => { const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file writeStream.write(data)
// When the stream is finished, resume with success writeStream.on("finish", () => resume(Effect.void))
// In case of an error during writing, resume with failure writeStream.on("error", (err) => resume(Effect.fail(err)))
// 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 programEffect.runPromise(program)// Output:// Cleaning up example.txt
Example (Handling Interruption with AbortSignal)
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignalconst interruptibleTask = Effect.async((resume, signal) => { // Handle interruption signal.addEventListener("abort", () => { console.log("Abort signal received") clearTimeout(timeoutId) })
// Simulate a long-running task const timeoutId = setTimeout(() => { console.log("Operation completed") resume(Effect.void) }, 2000)})
const program = Effect.gen(function* () { const fiber = yield* Effect.fork(interruptibleTask) // Simulate interrupting the fiber after 1 second yield* Effect.sleep("1 second") yield* Fiber.interrupt(fiber)})
// Run the programEffect.runPromise(program)// Output:// Abort signal received@since ― 2.0.0asyncBuffer, interface ErrorError>((resume: (_: Effect.Effect, Error, never>) => voidresume) => {6 module "node:fs"NodeFS.function readFile(path: NodeFS.PathOrFileDescriptor, callback: (err: NodeJS.ErrnoException | null, data: Buffer) => void): void (+3 overloads)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.readFile(filename: stringfilename, (error: NodeJS.ErrnoException | nullerror, data: Bufferdata) => {7 if (error: NodeJS.ErrnoException | nullerror) {8 // Resume with a failed Effect if an error occurs9 resume: (_: Effect.Effect, Error, never>) => voidresume(import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fail: (error: NodeJS.ErrnoException) => Effect.EffectCreates 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
.
Example (Creating a Failed Effect)
import { Effect } from "effect"
// ┌─── Effect// ▼const failure = Effect.fail( new Error("Operation failed due to network error"))@see ― succeed to create an effect that represents a successful value.@since ― 2.0.0fail(error: NodeJS.ErrnoExceptionerror))10 } else {11 // Resume with a succeeded Effect if successful12 resume: (_: Effect.Effect, Error, never>) => voidresume(import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const succeed: >(value: Buffer) => Effect.Effect, never, never>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.
Example (Creating a Successful Effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario//// ┌─── Effect// ▼const success = Effect.succeed(42)@see ― fail to create an effect that represents a failure.@since ― 2.0.0succeed(data: Bufferdata))13 }14 })15 })16
17// ┌─── Effect18// ▼19const const program: Effect.Effect, Error, never>program = const readFile: (filename: string) => Effect.Effect, Error, never>readFile("example.txt")
In the above example, we manually annotate the types when calling `Effect.async`:
Effect.async((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.
**Example** (Ignoring Subsequent `resume` Calls)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect } from "effect"2
3const const program: Effect.Effectprogram = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const async: (resume: (callback: (_: Effect.Effect) => void, signal: AbortSignal) => void | Effect.Effect, blockingOn?: FiberId) => Effect.Effect<...>Creates an Effect from a callback-based asynchronous function.
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.
When to Use
Use Effect.async when dealing with APIs that use callback-style instead of
async/await or Promise.
Example (Wrapping a Callback API)
import { Effect } from "effect"import * as NodeFS from "node:fs"
const readFile = (filename: string) => Effect.async((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// ▼const program = readFile("example.txt")
Example (Handling Interruption with Cleanup)
import { Effect, Fiber } from "effect"import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a fileconst writeFileWithCleanup = (filename: string, data: string) => Effect.async((resume) => { const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file writeStream.write(data)
// When the stream is finished, resume with success writeStream.on("finish", () => resume(Effect.void))
// In case of an error during writing, resume with failure writeStream.on("error", (err) => resume(Effect.fail(err)))
// 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 programEffect.runPromise(program)// Output:// Cleaning up example.txt
Example (Handling Interruption with AbortSignal)
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignalconst interruptibleTask = Effect.async((resume, signal) => { // Handle interruption signal.addEventListener("abort", () => { console.log("Abort signal received") clearTimeout(timeoutId) })
// Simulate a long-running task const timeoutId = setTimeout(() => { console.log("Operation completed") resume(Effect.void) }, 2000)})
const program = Effect.gen(function* () { const fiber = yield* Effect.fork(interruptibleTask) // Simulate interrupting the fiber after 1 second yield* Effect.sleep("1 second") yield* Fiber.interrupt(fiber)})
// Run the programEffect.runPromise(program)// Output:// Abort signal received@since ― 2.0.0async((resume: (_: Effect.Effect) => voidresume) => {4 resume: (_: Effect.Effect) => voidresume(import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const succeed: (value: number) => Effect.EffectCreates 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.
Example (Creating a Successful Effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario//// ┌─── Effect// ▼const success = Effect.succeed(42)@see ― fail to create an effect that represents a failure.@since ― 2.0.0succeed(1))5 resume: (_: Effect.Effect) => voidresume(import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const succeed: (value: number) => Effect.EffectCreates 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.
Example (Creating a Successful Effect)
import { Effect } from "effect"
// Creating an effect that represents a successful scenario//// ┌─── Effect// ▼const success = Effect.succeed(42)@see ― fail to create an effect that represents a failure.@since ― 2.0.0succeed(2)) // This line will be ignored6})7
8// Run the program9import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const runPromise: (effect: Effect.Effect, options?: { readonly signal?: AbortSignal;} | undefined) => PromiseExecutes an effect and returns the result as a Promise.
Details
This function runs an effect and converts its result into a Promise. If the
effect succeeds, the Promise will resolve with the successful result. If
the effect fails, the Promise will reject with an error, which includes the
failure details of the effect.
The optional options parameter allows you to pass an AbortSignal for
cancellation, enabling more fine-grained control over asynchronous tasks.
When to Use
Use this function when you need to execute an effect and work with its result
in a promise-based system, such as when integrating with third-party
libraries that expect Promise results.
Example (Running a Successful Effect as a Promise)
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)// Output: 1
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@see ― runPromiseExit for a version that returns an Exit type instead
of rejecting.@since ― 2.0.0runPromise(const program: Effect.Effectprogram).Promise.then(onfulfilled?: ((value: number) => void | PromiseLike) | null | undefined, onrejected?: ((reason: any) => PromiseLike) | null | undefined): 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: ConsoleThe 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 stdoutconsole.log('hello %s', 'world');// Prints: hello world, to stdoutconsole.error(new Error('Whoops, something bad happened'));// Prints error message and stack trace to stderr:// Error: Whoops, something bad happened// at [eval]:5:15// at Script.runInThisContext (node:vm:132:18)// at Object.runInThisContext (node:vm:309:38)// at node:internal/process/execution:77:19// at [eval]-wrapper:6:22// at evalScript (node:internal/process/execution:76:60)// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';console.warn(`Danger ${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out = getStreamSomehow();const err = getStreamSomehow();const myConsole = new console.Console(out, err);
myConsole.log('hello world');// Prints: hello world, to outmyConsole.log('hello %s', 'world');// Prints: hello world, to outmyConsole.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@see ― sourceconsole.Console.log(message?: any, ...optionalParams: any[]): voidPrints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const count = 5;console.log('count: %d', count);// Prints: count: 5, to stdoutconsole.log('count:', count);// Prints: count: 5, to stdout
See util.format() for more information.@since ― v0.1.100log) // Output: 1
### Advanced Usage
[](#advanced-usage)
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.
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect, import FiberFiber } from "effect"2import * as module "node:fs"NodeFS from "node:fs"3
4// Simulates a long-running operation to write to a file5const const writeFileWithCleanup: (filename: string, data: string) => Effect.EffectwriteFileWithCleanup = (filename: stringfilename: string, data: stringdata: string) =>6 import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const async: (resume: (callback: (_: Effect.Effect) => void, signal: AbortSignal) => void | Effect.Effect, blockingOn?: FiberId) => Effect.Effect<...>Creates an Effect from a callback-based asynchronous function.
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.
When to Use
Use Effect.async when dealing with APIs that use callback-style instead of
async/await or Promise.
Example (Wrapping a Callback API)
import { Effect } from "effect"import * as NodeFS from "node:fs"
const readFile = (filename: string) => Effect.async((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// ▼const program = readFile("example.txt")
Example (Handling Interruption with Cleanup)
import { Effect, Fiber } from "effect"import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a fileconst writeFileWithCleanup = (filename: string, data: string) => Effect.async((resume) => { const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file writeStream.write(data)
// When the stream is finished, resume with success writeStream.on("finish", () => resume(Effect.void))
// In case of an error during writing, resume with failure writeStream.on("error", (err) => resume(Effect.fail(err)))
// 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 programEffect.runPromise(program)// Output:// Cleaning up example.txt
Example (Handling Interruption with AbortSignal)
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignalconst interruptibleTask = Effect.async((resume, signal) => { // Handle interruption signal.addEventListener("abort", () => { console.log("Abort signal received") clearTimeout(timeoutId) })
// Simulate a long-running task const timeoutId = setTimeout(() => { console.log("Operation completed") resume(Effect.void) }, 2000)})
const program = Effect.gen(function* () { const fiber = yield* Effect.fork(interruptibleTask) // Simulate interrupting the fiber after 1 second yield* Effect.sleep("1 second") yield* Fiber.interrupt(fiber)})
// Run the programEffect.runPromise(program)// Output:// Abort signal received@since ― 2.0.0async((resume: (_: Effect.Effect) => voidresume) => {7 const const writeStream: NodeFS.WriteStreamwriteStream = module "node:fs"NodeFS.function createWriteStream(path: NodeFS.PathLike, options?: BufferEncoding | WriteStreamOptions): NodeFS.WriteStreamoptions 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.@since ― v0.1.31createWriteStream(filename: stringfilename)8
9 // Start writing data to the file10 const writeStream: NodeFS.WriteStreamwriteStream.WritableBase.write(chunk: any, callback?: (error: Error | null | undefined) => void): boolean (+1 overload)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:
function write(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: stringdata)11
12 // When the stream is finished, resume with success13 const writeStream: NodeFS.WriteStreamwriteStream.WriteStream.on(event: "finish", listener: () => void): NodeFS.WriteStream (+8 overloads)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.
import { EventEmitter } from 'node:events';const myEE = new EventEmitter();myEE.on('foo', () => console.log('a'));myEE.prependListener('foo', () => console.log('b'));myEE.emit('foo');// Prints:// b// aon("finish", () => resume: (_: Effect.Effect) => voidresume(import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const void: Effect.Effectexport voidRepresents an effect that does nothing and produces no value.
When to Use
Use this effect when you need to represent an effect that does nothing.
This is useful in scenarios where you need to satisfy an effect-based
interface or control program flow without performing any operations. For
example, it can be used in situations where you want to return an effect
from a function but do not need to compute or return any result.@since ― 2.0.0void))14
15 // In case of an error during writing, resume with failure16 const writeStream: NodeFS.WriteStreamwriteStream.WriteStream.on(event: "error", listener: (err: Error) => void): NodeFS.WriteStream (+8 overloads)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.
import { EventEmitter } from 'node:events';const myEE = new EventEmitter();myEE.on('foo', () => console.log('a'));myEE.prependListener('foo', () => console.log('b'));myEE.emit('foo');// Prints:// b// aon("error", (err: Errorerr) => resume: (_: Effect.Effect) => voidresume(import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fail: (error: Error) => Effect.EffectCreates 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
.
Example (Creating a Failed Effect)
import { Effect } from "effect"
// ┌─── Effect// ▼const failure = Effect.fail( new Error("Operation failed due to network error"))@see ― succeed to create an effect that represents a successful value.@since ― 2.0.0fail(err: Errorerr)))17
18 // Handle interruption by returning a cleanup effect19 return import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const sync: (thunk: LazyArg) => Effect.EffectCreates an Effect that represents a synchronous side-effectful computation.
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
.
When to Use
Use this function when you are sure the operation will not fail.
Example (Logging a Message)
import { Effect } from "effect"
const log = (message: string) => Effect.sync(() => { console.log(message) // side effect })
// ┌─── Effect// ▼const program = log("Hello, World!")@see ― try_try for a version that can handle failures.@since ― 2.0.0sync(() => {20 var console: ConsoleThe 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 stdoutconsole.log('hello %s', 'world');// Prints: hello world, to stdoutconsole.error(new Error('Whoops, something bad happened'));// Prints error message and stack trace to stderr:// Error: Whoops, something bad happened// at [eval]:5:15// at Script.runInThisContext (node:vm:132:18)// at Object.runInThisContext (node:vm:309:38)// at node:internal/process/execution:77:19// at [eval]-wrapper:6:22// at evalScript (node:internal/process/execution:76:60)// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';console.warn(`Danger ${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out = getStreamSomehow();const err = getStreamSomehow();const myConsole = new console.Console(out, err);
myConsole.log('hello world');// Prints: hello world, to outmyConsole.log('hello %s', 'world');// Prints: hello world, to outmyConsole.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@see ― sourceconsole.Console.log(message?: any, ...optionalParams: any[]): voidPrints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const count = 5;console.log('count: %d', count);// Prints: count: 5, to stdoutconsole.log('count:', count);// Prints: count: 5, to stdout
See util.format() for more information.@since ― v0.1.100log(`Cleaning up ${filename: stringfilename}`)21 module "node:fs"NodeFS.function unlinkSync(path: NodeFS.PathLike): voidSynchronous unlink(2). Returns undefined.@since ― v0.1.21unlinkSync(filename: stringfilename)22 })23 })24
25const const program: Effect.Effectprogram = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const gen: >, void>(f: (resume: Effect.Adapter) => Generator>, void, never>) => Effect.Effect<...> (+1 overload)Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
Effect.gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
Example
import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = ( total: number, discountRate: number): Effect.Effect => discountRate === 0 ? Effect.fail(new Error("Discount rate cannot be zero")) : Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () { const transactionAmount = yield* fetchTransactionAmount const discountRate = yield* fetchDiscountRate const discountedAmount = yield* applyDiscount( transactionAmount, discountRate ) const finalAmount = addServiceCharge(discountedAmount) return `Final amount to charge: ${finalAmount}`})@since ― 2.0.0gen(function* () {26 const const fiber: Fiber.RuntimeFiberfiber = yield* import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fork: (self: Effect.Effect) => Effect.Effect, never, never>Creates a new fiber to run an effect concurrently.
Details
This function takes an effect and forks it into a separate fiber, allowing it
to run concurrently without blocking the original effect. The new fiber
starts execution immediately after being created, and the fiber object is
returned immediately without waiting for the effect to begin. This is useful
when you want to run tasks concurrently while continuing other tasks in the
parent fiber.
The forked fiber is attached to the parent fiber's scope. This means that
when the parent fiber terminates, the child fiber will also be terminated
automatically. This feature, known as "auto supervision," ensures that no
fibers are left running unintentionally. If you prefer not to have this auto
supervision behavior, you can use
forkDaemon
or
forkIn
.
When to Use
Use this function when you need to run an effect concurrently without
blocking the current execution flow. For example, you might use it to launch
background tasks or concurrent computations. However, working with fibers can
be complex, so before using this function directly, you might want to explore
higher-level functions like
raceWith
,
zip
, or others that can
manage concurrency for you.
Example
import { Effect } from "effect"
const fib = (n: number): Effect.Effect => n < 2 ? Effect.succeed(n) : Effect.zipWith(fib(n - 1), fib(n - 2), (a, b) => a + b)
// ┌─── Effect, never, never>// ▼const fib10Fiber = Effect.fork(fib(10))@see ― forkWithErrorHandler for a version that allows you to handle errors.@since ― 2.0.0fork(27 const writeFileWithCleanup: (filename: string, data: string) => Effect.EffectwriteFileWithCleanup("example.txt", "Some long data...")28 )29 // Simulate interrupting the fiber after 1 second30 yield* import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const sleep: (duration: DurationInput) => Effect.EffectSuspends the execution of an effect for a specified Duration.
Details
This function pauses the execution of an effect for a given duration. It is
asynchronous, meaning that it does not block the fiber executing the effect.
Instead, the fiber is suspended during the delay period and can resume once
the specified time has passed.
The duration can be specified using various formats supported by the
Duration module, such as a string ("2 seconds") or numeric value
representing milliseconds.
Example
import { Effect } from "effect"
const program = Effect.gen(function*() { console.log("Starting task...") yield* Effect.sleep("3 seconds") // Waits for 3 seconds console.log("Task completed!")})
Effect.runFork(program)// Output:// Starting task...// Task completed!@since ― 2.0.0sleep("1 second")31 yield* import FiberFiber.const interrupt: (self: Fiber.Fiber) => Effect.Effect, never, never>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.@since ― 2.0.0interrupt(const fiber: Fiber.RuntimeFiberfiber) // This will trigger the cleanup32})33
34// Run the program35import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const runPromise: (effect: Effect.Effect, options?: { readonly signal?: AbortSignal;} | undefined) => PromiseExecutes an effect and returns the result as a Promise.
Details
This function runs an effect and converts its result into a Promise. If the
effect succeeds, the Promise will resolve with the successful result. If
the effect fails, the Promise will reject with an error, which includes the
failure details of the effect.
The optional options parameter allows you to pass an AbortSignal for
cancellation, enabling more fine-grained control over asynchronous tasks.
When to Use
Use this function when you need to execute an effect and work with its result
in a promise-based system, such as when integrating with third-party
libraries that expect Promise results.
Example (Running a Successful Effect as a Promise)
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)// Output: 1
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@see ― runPromiseExit for a version that returns an Exit type instead
of rejecting.@since ― 2.0.0runPromise(const program: Effect.Effectprogram)36/*37Output:38Cleaning up example.txt39*/
If the operation you’re wrapping supports interruption, the `resume` function can receive an `AbortSignal` to handle interruption requests directly.
**Example** (Handling Interruption with `AbortSignal`)
1import { import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect, import FiberFiber } from "effect"2
3// A task that supports interruption using AbortSignal4const const interruptibleTask: Effect.EffectinterruptibleTask = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const async: (resume: (callback: (_: Effect.Effect) => void, signal: AbortSignal) => void | Effect.Effect, blockingOn?: FiberId) => Effect.Effect<...>Creates an Effect from a callback-based asynchronous function.
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.
When to Use
Use Effect.async when dealing with APIs that use callback-style instead of
async/await or Promise.
Example (Wrapping a Callback API)
import { Effect } from "effect"import * as NodeFS from "node:fs"
const readFile = (filename: string) => Effect.async((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// ▼const program = readFile("example.txt")
Example (Handling Interruption with Cleanup)
import { Effect, Fiber } from "effect"import * as NodeFS from "node:fs"
// Simulates a long-running operation to write to a fileconst writeFileWithCleanup = (filename: string, data: string) => Effect.async((resume) => { const writeStream = NodeFS.createWriteStream(filename)
// Start writing data to the file writeStream.write(data)
// When the stream is finished, resume with success writeStream.on("finish", () => resume(Effect.void))
// In case of an error during writing, resume with failure writeStream.on("error", (err) => resume(Effect.fail(err)))
// 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 programEffect.runPromise(program)// Output:// Cleaning up example.txt
Example (Handling Interruption with AbortSignal)
import { Effect, Fiber } from "effect"
// A task that supports interruption using AbortSignalconst interruptibleTask = Effect.async((resume, signal) => { // Handle interruption signal.addEventListener("abort", () => { console.log("Abort signal received") clearTimeout(timeoutId) })
// Simulate a long-running task const timeoutId = setTimeout(() => { console.log("Operation completed") resume(Effect.void) }, 2000)})
const program = Effect.gen(function* () { const fiber = yield* Effect.fork(interruptibleTask) // Simulate interrupting the fiber after 1 second yield* Effect.sleep("1 second") yield* Fiber.interrupt(fiber)})
// Run the programEffect.runPromise(program)// Output:// Abort signal received@since ― 2.0.0async((resume: (_: Effect.Effect) => voidresume, signal: AbortSignalsignal) => {5 // Handle interruption6 signal: AbortSignalsignal.function addEventListener(type: string, listener: EventListener | EventListenerObject, options?: AddEventListenerOptions | boolean): voidAdds 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: ConsoleThe 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 stdoutconsole.log('hello %s', 'world');// Prints: hello world, to stdoutconsole.error(new Error('Whoops, something bad happened'));// Prints error message and stack trace to stderr:// Error: Whoops, something bad happened// at [eval]:5:15// at Script.runInThisContext (node:vm:132:18)// at Object.runInThisContext (node:vm:309:38)// at node:internal/process/execution:77:19// at [eval]-wrapper:6:22// at evalScript (node:internal/process/execution:76:60)// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';console.warn(`Danger ${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out = getStreamSomehow();const err = getStreamSomehow();const myConsole = new console.Console(out, err);
myConsole.log('hello world');// Prints: hello world, to outmyConsole.log('hello %s', 'world');// Prints: hello world, to outmyConsole.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@see ― sourceconsole.Console.log(message?: any, ...optionalParams: any[]): voidPrints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const count = 5;console.log('count: %d', count);// Prints: count: 5, to stdoutconsole.log('count:', count);// Prints: count: 5, to stdout
See util.format() for more information.@since ― v0.1.100log("Abort signal received")8 function clearTimeout(timeoutId: NodeJS.Timeout | string | number | undefined): voidCancels a Timeout object created by setTimeout().@since ― v0.0.1@param ― timeout A Timeout object as returned by setTimeout or the primitive of the Timeout object as a string or a number.clearTimeout(const timeoutId: NodeJS.TimeouttimeoutId)9 })10
11 // Simulate a long-running task12 const const timeoutId: NodeJS.TimeouttimeoutId = function setTimeout<[]>(callback: () => void, ms?: number): NodeJS.Timeout (+1 overload)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: ConsoleThe 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 stdoutconsole.log('hello %s', 'world');// Prints: hello world, to stdoutconsole.error(new Error('Whoops, something bad happened'));// Prints error message and stack trace to stderr:// Error: Whoops, something bad happened// at [eval]:5:15// at Script.runInThisContext (node:vm:132:18)// at Object.runInThisContext (node:vm:309:38)// at node:internal/process/execution:77:19// at [eval]-wrapper:6:22// at evalScript (node:internal/process/execution:76:60)// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';console.warn(`Danger ${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out = getStreamSomehow();const err = getStreamSomehow();const myConsole = new console.Console(out, err);
myConsole.log('hello world');// Prints: hello world, to outmyConsole.log('hello %s', 'world');// Prints: hello world, to outmyConsole.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@see ― sourceconsole.Console.log(message?: any, ...optionalParams: any[]): voidPrints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const count = 5;console.log('count: %d', count);// Prints: count: 5, to stdoutconsole.log('count:', count);// Prints: count: 5, to stdout
See util.format() for more information.@since ― v0.1.100log("Operation completed")14 resume: (_: Effect.Effect) => voidresume(import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const void: Effect.Effectexport voidRepresents an effect that does nothing and produces no value.
When to Use
Use this effect when you need to represent an effect that does nothing.
This is useful in scenarios where you need to satisfy an effect-based
interface or control program flow without performing any operations. For
example, it can be used in situations where you want to return an effect
from a function but do not need to compute or return any result.@since ― 2.0.0void)15 }, 2000)16})17
18const const program: Effect.Effectprogram = import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const gen: >, void>(f: (resume: Effect.Adapter) => Generator>, void, never>) => Effect.Effect<...> (+1 overload)Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
Effect.gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
Example
import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = ( total: number, discountRate: number): Effect.Effect => discountRate === 0 ? Effect.fail(new Error("Discount rate cannot be zero")) : Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () { const transactionAmount = yield* fetchTransactionAmount const discountRate = yield* fetchDiscountRate const discountedAmount = yield* applyDiscount( transactionAmount, discountRate ) const finalAmount = addServiceCharge(discountedAmount) return `Final amount to charge: ${finalAmount}`})@since ― 2.0.0gen(function* () {19 const const fiber: Fiber.RuntimeFiberfiber = yield* import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const fork: (self: Effect.Effect) => Effect.Effect, never, never>Creates a new fiber to run an effect concurrently.
Details
This function takes an effect and forks it into a separate fiber, allowing it
to run concurrently without blocking the original effect. The new fiber
starts execution immediately after being created, and the fiber object is
returned immediately without waiting for the effect to begin. This is useful
when you want to run tasks concurrently while continuing other tasks in the
parent fiber.
The forked fiber is attached to the parent fiber's scope. This means that
when the parent fiber terminates, the child fiber will also be terminated
automatically. This feature, known as "auto supervision," ensures that no
fibers are left running unintentionally. If you prefer not to have this auto
supervision behavior, you can use
forkDaemon
or
forkIn
.
When to Use
Use this function when you need to run an effect concurrently without
blocking the current execution flow. For example, you might use it to launch
background tasks or concurrent computations. However, working with fibers can
be complex, so before using this function directly, you might want to explore
higher-level functions like
raceWith
,
zip
, or others that can
manage concurrency for you.
Example
import { Effect } from "effect"
const fib = (n: number): Effect.Effect => n < 2 ? Effect.succeed(n) : Effect.zipWith(fib(n - 1), fib(n - 2), (a, b) => a + b)
// ┌─── Effect, never, never>// ▼const fib10Fiber = Effect.fork(fib(10))@see ― forkWithErrorHandler for a version that allows you to handle errors.@since ― 2.0.0fork(const interruptibleTask: Effect.EffectinterruptibleTask)20 // Simulate interrupting the fiber after 1 second21 yield* import Effect@since ― 2.0.0@since ― 2.0.0@since ― 2.0.0Effect.const sleep: (duration: DurationInput) => Effect.EffectSuspends the execution of an effect for a specified Duration.
Details
This function pauses the execution of an effect for a given duration. It is
asynchronous, meaning that it does not block the fiber executing the effect.
Instead, the fiber is suspended during the delay period and can resume once
the specified time has passed.
The duration can be specified using various formats supported by the
Duration module, such as a string ("2 seconds") or numeric value
representing milliseconds.
Example
import { Effect } from "effect"
const program = Effect.gen(function*() { console.log("Starting task...") yield* Effect.sleep("3 seconds") // Waits for 3 seconds console.log("Task completed!")})
Effect.runFork(program)// Output:// Starting task...// Task completed!@since ― 2.0.0sleep("1 second")22 yield* import FiberFiber.const interrupt: (self: Fiber.Fiber