Skip to content

作用域

Scope 数据类型是 Effect 中以安全和可组合方式管理资源的核心构造。

作用域表示一个或多个资源的生命周期。当作用域关闭时,其中的所有资源都会被释放,确保没有资源泄漏。作用域还允许添加终结器,用于定义如何释放资源。

使用 Scope 数据类型,您可以:

  • 添加终结器:终结器指定资源的清理逻辑。
  • 关闭作用域:当作用域关闭时,所有资源都会被释放,终结器会被执行。

示例(管理作用域)

import {
import Scope
Scope
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
,
import Exit
Exit
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
// 创建一个新的作用域
import Scope
Scope
.
const make: (executionStrategy?: ExecutionStrategy) => Effect.Effect<Scope.CloseableScope>

Creates a new closeable scope where finalizers will run according to the specified ExecutionStrategy. If no execution strategy is provided, sequential will be used by default.

@since2.0.0

make
().
Pipeable.pipe<Effect.Effect<Scope.CloseableScope, never, never>, Effect.Effect<Scope.CloseableScope, never, never>, Effect.Effect<Scope.CloseableScope, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Scope.CloseableScope, never, never>) => Effect.Effect<Scope.CloseableScope, never, never>, bc: (_: Effect.Effect<Scope.CloseableScope, never, never>) => Effect.Effect<Scope.CloseableScope, never, never>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
// 添加终结器 1
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tap: <Scope.CloseableScope, Effect.Effect<void, never, never>>(f: (a: Scope.CloseableScope) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<Scope.CloseableScope, E, R>) => Effect.Effect<Scope.CloseableScope, E, R> (+7 overloads)

Runs a side effect with the result of an effect without changing the original value.

Details

This function works similarly to flatMap, but it ignores the result of the function passed to it. The value from the previous effect remains available for the next part of the chain. Note that if the side effect fails, the entire chain will fail too.

When to Use

Use this function when you want to perform a side effect, like logging or tracking, without modifying the main value. This is useful when you need to observe or record an action but want the original value to be passed to the next step.

Example (Logging a step in a pipeline)

import { Console, Effect, pipe } from "effect"
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
// Log the fetched transaction amount
Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)),
// `amount` is still available!
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(finalAmount).then(console.log)
// Output:
// Apply a discount to: 100
// 95

@seeflatMap for a version that allows you to change the value.

@since2.0.0

tap
((
scope: Scope.CloseableScope
scope
) =>
import Scope
Scope
.
const addFinalizer: (self: Scope.Scope, finalizer: Effect.Effect<unknown>) => Effect.Effect<void>

Adds a finalizer to this scope. The finalizer is guaranteed to be run when the scope is closed. Use this when the finalizer does not need to know the Exit value that the scope is closed with.

@seeaddFinalizerExit

@since2.0.0

addFinalizer
(
scope: Scope.CloseableScope
scope
,
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("终结器 1"))
),
// 添加终结器 2
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tap: <Scope.CloseableScope, Effect.Effect<void, never, never>>(f: (a: Scope.CloseableScope) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<Scope.CloseableScope, E, R>) => Effect.Effect<Scope.CloseableScope, E, R> (+7 overloads)

Runs a side effect with the result of an effect without changing the original value.

Details

This function works similarly to flatMap, but it ignores the result of the function passed to it. The value from the previous effect remains available for the next part of the chain. Note that if the side effect fails, the entire chain will fail too.

When to Use

Use this function when you want to perform a side effect, like logging or tracking, without modifying the main value. This is useful when you need to observe or record an action but want the original value to be passed to the next step.

Example (Logging a step in a pipeline)

import { Console, Effect, pipe } from "effect"
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
// Log the fetched transaction amount
Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)),
// `amount` is still available!
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(finalAmount).then(console.log)
// Output:
// Apply a discount to: 100
// 95

@seeflatMap for a version that allows you to change the value.

@since2.0.0

tap
((
scope: Scope.CloseableScope
scope
) =>
import Scope
Scope
.
const addFinalizer: (self: Scope.Scope, finalizer: Effect.Effect<unknown>) => Effect.Effect<void>

Adds a finalizer to this scope. The finalizer is guaranteed to be run when the scope is closed. Use this when the finalizer does not need to know the Exit value that the scope is closed with.

@seeaddFinalizerExit

@since2.0.0

addFinalizer
(
scope: Scope.CloseableScope
scope
,
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("终结器 2"))
),
// 关闭作用域
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const andThen: <Scope.CloseableScope, Effect.Effect<void, never, never>>(f: (a: Scope.CloseableScope) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<Scope.CloseableScope, E, R>) => Effect.Effect<void, E, R> (+3 overloads)

Chains two actions, where the second action can depend on the result of the first.

Syntax

const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect))
// or
const transformedEffect = Effect.andThen(myEffect, anotherEffect)
// or
const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect))

When to Use

Use andThen when you need to run multiple actions in sequence, with the second action depending on the result of the first. This is useful for combining effects or handling computations that must happen in order.

Details

The second action can be:

  • A constant value (similar to

as

)

  • A function returning a value (similar to

map

)

  • A Promise
  • A function returning a Promise
  • An Effect
  • A function returning an Effect (similar to

flatMap

)

Note: andThen works well with both Option and Either types, treating them as effects.

Example (Applying a Discount Based on Fetched Amount)

import { pipe, Effect } from "effect"
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
// Using Effect.map and Effect.flatMap
const result1 = pipe(
fetchTransactionAmount,
Effect.map((amount) => amount * 2),
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(result1).then(console.log)
// Output: 190
// Using Effect.andThen
const result2 = pipe(
fetchTransactionAmount,
Effect.andThen((amount) => amount * 2),
Effect.andThen((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(result2).then(console.log)
// Output: 190

@since2.0.0

andThen
((
scope: Scope.CloseableScope
scope
) =>
import Scope
Scope
.
const close: (self: Scope.CloseableScope, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void>

Closes this scope with the specified exit value, running all finalizers that have been added to the scope.

@since2.0.0

close
(
scope: Scope.CloseableScope
scope
,
import Exit
Exit
.
const succeed: <string>(value: string) => Exit.Exit<string, never>

Constructs a new Exit.Success containing the specified value of type A.

@since2.0.0

succeed
("作用域成功关闭"))
)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

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

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

When to Use

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

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const program: Effect.Effect<void, never, never>
program
)
/*
输出:
终结器 2 <-- 终结器按相反顺序关闭
终结器 1
*/

在上面的示例中,终结器被添加到作用域中,当作用域关闭时,终结器按相反顺序执行

这种相反顺序很重要,因为它确保资源按正确的顺序释放。

例如,如果您获取了一个网络连接,然后访问远程服务器上的文件,必须在关闭网络连接之前先关闭文件,以避免错误。

Effect.addFinalizer 函数是一个高级 API,允许您向 Effect 的作用域添加终结器。终结器是一段代码,保证在关联的作用域关闭时运行。终结器的行为可以根据 Exit 值而变化,该值表示作用域是如何关闭的——是成功关闭还是出现错误。

示例(在成功时添加终结器)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const
const program: Effect.Effect<string, never, Scope>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
((
exit: Exit<unknown, unknown>
exit
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`终结器已执行。退出状态:${
exit: Exit<unknown, unknown>
exit
.
_tag: "Success" | "Failure"
_tag
}`)
)
return "some result"
})
// 将 Effect 包装在作用域中
//
// ┌─── Effect<string, never, never>
// ▼
const
const runnable: Effect.Effect<string, never, never>
runnable
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <string, never, Scope>(effect: Effect.Effect<string, never, Scope>) => Effect.Effect<string, never, never>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
(
const program: Effect.Effect<string, never, Scope>
program
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Runs an effect and returns a Promise that resolves to an Exit, representing the outcome.

Details

This function executes an effect and resolves to an Exit object. The Exit type provides detailed information about the result of the effect:

  • If the effect succeeds, the Exit will be of type Success and include the value produced by the effect.
  • If the effect fails, the Exit will be of type Failure and contain a Cause object, detailing the failure.

Using this function allows you to examine both successful results and failure cases in a unified way, while still leveraging Promise for handling the asynchronous behavior of the effect.

When to Use

Use this function when you need to understand the outcome of an effect, whether it succeeded or failed, and want to work with this result using Promise syntax. This is particularly useful when integrating with systems that rely on promises but need more detailed error handling than a simple rejection.

Example (Handling Results as Exit)

import { Effect } from "effect"
// Execute a successful effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.succeed(1)).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Success",
// value: 1
// }
// Execute a failing effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.fail("my error")).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Failure",
// cause: {
// _id: "Cause",
// _tag: "Fail",
// failure: "my error"
// }
// }

@since2.0.0

runPromiseExit
(
const runnable: Effect.Effect<string, never, never>
runnable
).
Promise<Exit<string, never>>.then<void, never>(onfulfilled?: ((value: Exit<string, never>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<void>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
(
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
)
/*
输出:
终结器已执行。退出状态:Success
{ _id: 'Exit', _tag: 'Success', value: 'some result' }
*/

在此示例中,我们使用 Effect.addFinalizer 添加一个终结器,该终结器在作用域关闭后记录退出状态。终结器将在 Effect 完成时执行,并记录 Effect 是成功完成还是失败。

类型签名:

const program: Effect<string, never, Scope>

显示工作流需要一个 Scope 来运行。您可以使用 Effect.scoped 函数提供此 Scope,该函数创建一个新的作用域,在其中运行 Effect,并确保在作用域关闭时执行终结器。

示例(在失败时添加终结器)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const
const program: Effect.Effect<never, string, Scope>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
((
exit: Exit<unknown, unknown>
exit
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`终结器已执行。退出状态:${
exit: Exit<unknown, unknown>
exit
.
_tag: "Success" | "Failure"
_tag
}`)
)
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

Example (Creating a Failed Effect)

import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@seesucceed to create an effect that represents a successful value.

@since2.0.0

fail
("Uh oh!")
})
// 将 Effect 包装在作用域中
//
// ┌─── Effect<never, string, never>
// ▼
const
const runnable: Effect.Effect<never, string, never>
runnable
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <never, string, Scope>(effect: Effect.Effect<never, string, Scope>) => Effect.Effect<never, string, never>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
(
const program: Effect.Effect<never, string, Scope>
program
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Runs an effect and returns a Promise that resolves to an Exit, representing the outcome.

Details

This function executes an effect and resolves to an Exit object. The Exit type provides detailed information about the result of the effect:

  • If the effect succeeds, the Exit will be of type Success and include the value produced by the effect.
  • If the effect fails, the Exit will be of type Failure and contain a Cause object, detailing the failure.

Using this function allows you to examine both successful results and failure cases in a unified way, while still leveraging Promise for handling the asynchronous behavior of the effect.

When to Use

Use this function when you need to understand the outcome of an effect, whether it succeeded or failed, and want to work with this result using Promise syntax. This is particularly useful when integrating with systems that rely on promises but need more detailed error handling than a simple rejection.

Example (Handling Results as Exit)

import { Effect } from "effect"
// Execute a successful effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.succeed(1)).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Success",
// value: 1
// }
// Execute a failing effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.fail("my error")).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Failure",
// cause: {
// _id: "Cause",
// _tag: "Fail",
// failure: "my error"
// }
// }

@since2.0.0

runPromiseExit
(
const runnable: Effect.Effect<never, string, never>
runnable
).
Promise<Exit<never, string>>.then<void, never>(onfulfilled?: ((value: Exit<never, string>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<void>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
(
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
)
/*
输出:
终结器已执行。退出状态:Failure
{
_id: 'Exit',
_tag: 'Failure',
cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
}
*/

在这种情况下,即使 Effect 失败,终结器也会执行。日志输出反映了终结器在失败后运行,并记录失败详情。

示例(在中断时添加终结器)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const
const program: Effect.Effect<never, never, Scope>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
((
exit: Exit<unknown, unknown>
exit
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`终结器已执行。退出状态:${
exit: Exit<unknown, unknown>
exit
.
_tag: "Success" | "Failure"
_tag
}`)
)
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const interrupt: Effect.Effect<never, never, never>

Represents an effect that interrupts the current fiber.

Details

This effect models the explicit interruption of the fiber in which it runs. When executed, it causes the fiber to stop its operation immediately, capturing the interruption details such as the fiber's ID and its start time. The resulting interruption can be observed in the Exit type if the effect is run with functions like

runPromiseExit

.

Example

import { Effect } from "effect"
const program = Effect.gen(function* () {
console.log("start")
yield* Effect.sleep("2 seconds")
yield* Effect.interrupt
console.log("done")
return "some result"
})
Effect.runPromiseExit(program).then(console.log)
// Output:
// start
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@since2.0.0

interrupt
})
// 将 Effect 包装在作用域中
//
// ┌─── Effect<never, never, never>
// ▼
const
const runnable: Effect.Effect<never, never, never>
runnable
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <never, never, Scope>(effect: Effect.Effect<never, never, Scope>) => Effect.Effect<never, never, never>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
(
const program: Effect.Effect<never, never, Scope>
program
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Runs an effect and returns a Promise that resolves to an Exit, representing the outcome.

Details

This function executes an effect and resolves to an Exit object. The Exit type provides detailed information about the result of the effect:

  • If the effect succeeds, the Exit will be of type Success and include the value produced by the effect.
  • If the effect fails, the Exit will be of type Failure and contain a Cause object, detailing the failure.

Using this function allows you to examine both successful results and failure cases in a unified way, while still leveraging Promise for handling the asynchronous behavior of the effect.

When to Use

Use this function when you need to understand the outcome of an effect, whether it succeeded or failed, and want to work with this result using Promise syntax. This is particularly useful when integrating with systems that rely on promises but need more detailed error handling than a simple rejection.

Example (Handling Results as Exit)

import { Effect } from "effect"
// Execute a successful effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.succeed(1)).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Success",
// value: 1
// }
// Execute a failing effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.fail("my error")).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Failure",
// cause: {
// _id: "Cause",
// _tag: "Fail",
// failure: "my error"
// }
// }

@since2.0.0

runPromiseExit
(
const runnable: Effect.Effect<never, never, never>
runnable
).
Promise<Exit<never, never>>.then<void, never>(onfulfilled?: ((value: Exit<never, never>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<void>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
(
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
)
/*
输出:
终结器已执行。退出状态:Failure
{
_id: 'Exit',
_tag: 'Failure',
cause: {
_id: 'Cause',
_tag: 'Interrupt',
fiberId: {
_id: 'FiberId',
_tag: 'Runtime',
id: 0,
startTimeMillis: ...
}
}
}
*/

此示例显示了当 Effect 被中断时终结器的行为。终结器在中断后运行,退出状态反映了 Effect 在执行过程中被停止。

当您在单个操作中使用多个作用域资源时,了解它们的作用域如何交互非常重要。 默认情况下,这些作用域会合并为一个,但您可以通过手动创建和关闭它们来更精细地控制每个作用域何时关闭。

让我们首先看看作用域默认是如何合并的:

示例(合并作用域)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
} from "effect"
const
const task1: Effect.Effect<void, never, Scope>
task1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("任务 1")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
(() =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("任务 1 后的终结器"))
})
const
const task2: Effect.Effect<void, never, Scope>
task2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("任务 2")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
(() =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("任务 2 后的终结器"))
})
const
const program: Effect.Effect<void, never, Scope>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
// 两个任务的作用域合并为一个
yield*
const task1: Effect.Effect<void, never, Scope>
task1
yield*
const task2: Effect.Effect<void, never, Scope>
task2
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

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

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

When to Use

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

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <void, never, Scope>(effect: Effect.Effect<void, never, Scope>) => Effect.Effect<void, never, never>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
(
const program: Effect.Effect<void, never, Scope>
program
))
/*
输出:
任务 1
任务 2
任务 2 后的终结器
任务 1 后的终结器
*/

在这种情况下,task1task2 的作用域合并为单个作用域,当程序运行时,它按特定顺序输出任务及其终结器。

如果您想更好地控制每个作用域何时关闭,可以手动创建和关闭它们:

示例(手动创建和关闭作用域)

import {
import Console
Console
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Exit
Exit
,
import Scope
Scope
} from "effect"
const
const task1: Effect.Effect<void, never, Scope.Scope>
task1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("任务 1")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope.Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
(() =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("任务 1 后的终结器"))
})
const
const task2: Effect.Effect<void, never, Scope.Scope>
task2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("任务 2")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope.Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
(() =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("任务 2 后的终结器"))
})
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const scope1: Scope.CloseableScope
scope1
= yield*
import Scope
Scope
.
const make: (executionStrategy?: ExecutionStrategy) => Effect.Effect<Scope.CloseableScope>

Creates a new closeable scope where finalizers will run according to the specified ExecutionStrategy. If no execution strategy is provided, sequential will be used by default.

@since2.0.0

make
()
const
const scope2: Scope.CloseableScope
scope2
= yield*
import Scope
Scope
.
const make: (executionStrategy?: ExecutionStrategy) => Effect.Effect<Scope.CloseableScope>

Creates a new closeable scope where finalizers will run according to the specified ExecutionStrategy. If no execution strategy is provided, sequential will be used by default.

@since2.0.0

make
()
// 将 task1 的作用域扩展到 scope1
yield*
const task1: Effect.Effect<void, never, Scope.Scope>
task1
.
Pipeable.pipe<Effect.Effect<void, never, Scope.Scope>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, Scope.Scope>, ab: (_: Effect.Effect<void, never, Scope.Scope>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Scope
Scope
.
const extend: (scope: Scope.Scope) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope.Scope>> (+1 overload)

Extends the scope of an Effect that requires a scope into this scope. It provides this scope to the effect but does not close the scope when the effect completes execution. This allows extending a scoped value into a larger scope.

@since2.0.0

extend
(
const scope1: Scope.CloseableScope
scope1
))
// 将 task2 的作用域扩展到 scope2
yield*
const task2: Effect.Effect<void, never, Scope.Scope>
task2
.
Pipeable.pipe<Effect.Effect<void, never, Scope.Scope>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, Scope.Scope>, ab: (_: Effect.Effect<void, never, Scope.Scope>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Scope
Scope
.
const extend: (scope: Scope.Scope) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope.Scope>> (+1 overload)

Extends the scope of an Effect that requires a scope into this scope. It provides this scope to the effect but does not close the scope when the effect completes execution. This allows extending a scoped value into a larger scope.

@since2.0.0

extend
(
const scope2: Scope.CloseableScope
scope2
))
// 手动关闭 scope1 和 scope2
yield*
import Scope
Scope
.
const close: (self: Scope.CloseableScope, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void>

Closes this scope with the specified exit value, running all finalizers that have been added to the scope.

@since2.0.0

close
(
const scope1: Scope.CloseableScope
scope1
,
import Exit
Exit
.
const void: Exit.Exit<void, never>
export void

Represents an Exit which succeeds with undefined.

@since2.0.0

void
)
yield*
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("做其他事情")
yield*
import Scope
Scope
.
const close: (self: Scope.CloseableScope, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void>

Closes this scope with the specified exit value, running all finalizers that have been added to the scope.

@since2.0.0

close
(
const scope2: Scope.CloseableScope
scope2
,
import Exit
Exit
.
const void: Exit.Exit<void, never>
export void

Represents an Exit which succeeds with undefined.

@since2.0.0

void
)
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

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

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

When to Use

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

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const program: Effect.Effect<void, never, never>
program
)
/*
输出:
任务 1
任务 2
任务 1 后的终结器
做其他事情
任务 2 后的终结器
*/

在此示例中,我们创建了两个独立的作用域 scope1scope2,并将每个任务的作用域扩展到其各自的作用域中。当您运行程序时,它以不同的顺序输出任务及其终结器。

您可能想知道当作用域关闭时,但该作用域内的任务尚未完成时会发生什么。 需要注意的关键点是,作用域关闭不会强制任务被中断。

示例(关闭包含待处理任务的作用域)

import {
import Console
Console
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Exit
Exit
,
import Scope
Scope
} from "effect"
const
const task: Effect.Effect<void, never, Scope.Scope>
task
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Suspends the execution of an effect for a specified Duration.

Details

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

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

Example

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

@since2.0.0

sleep
("1 second")
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("已执行")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const addFinalizer: <void, never>(finalizer: (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, Scope.Scope>

Ensures a finalizer is added to the scope of the calling effect, guaranteeing it runs when the scope is closed.

Details

This function adds a finalizer that will execute whenever the scope of the effect is closed, regardless of whether the effect succeeds, fails, or is interrupted. The finalizer receives the Exit value of the effect's scope, allowing it to react differently depending on how the effect concludes.

Finalizers are a reliable way to manage resource cleanup, ensuring that resources such as file handles, network connections, or database transactions are properly closed even in the event of an unexpected interruption or error.

Finalizers operate in conjunction with Effect's scoped resources. If an effect with a finalizer is wrapped in a scope, the finalizer will execute automatically when the scope ends.

Example (Adding a Finalizer on Success)

import { Effect, Console } from "effect"
// ┌─── Effect<string, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return "some result"
})
// Wrapping the effect in a scope
//
// ┌─── Effect<string, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Success
// { _id: 'Exit', _tag: 'Success', value: 'some result' }

Example (Adding a Finalizer on Failure)

import { Effect, Console } from "effect"
// ┌─── Effect<never, string, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.fail("Uh oh!")
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, string, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' }
// }

Example (Adding a Finalizer on Interruption)

import { Effect, Console } from "effect"
// ┌─── Effect<never, never, Scope>
// ▼
const program = Effect.gen(function* () {
yield* Effect.addFinalizer((exit) =>
Console.log(`Finalizer executed. Exit status: ${exit._tag}`)
)
return yield* Effect.interrupt
})
// Wrapping the effect in a scope
//
// ┌─── Effect<never, never, never>
// ▼
const runnable = Effect.scoped(program)
Effect.runPromiseExit(runnable).then(console.log)
// Output:
// Finalizer executed. Exit status: Failure
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Interrupt',
// fiberId: {
// _id: 'FiberId',
// _tag: 'Runtime',
// id: 0,
// startTimeMillis: ...
// }
// }
// }

@seeonExit for attaching a finalizer directly to an effect.

@since2.0.0

addFinalizer
(() =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("任务终结器"))
})
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const scope: Scope.CloseableScope
scope
= yield*
import Scope
Scope
.
const make: (executionStrategy?: ExecutionStrategy) => Effect.Effect<Scope.CloseableScope>

Creates a new closeable scope where finalizers will run according to the specified ExecutionStrategy. If no execution strategy is provided, sequential will be used by default.

@since2.0.0

make
()
// 立即关闭作用域
yield*
import Scope
Scope
.
const close: (self: Scope.CloseableScope, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void>

Closes this scope with the specified exit value, running all finalizers that have been added to the scope.

@since2.0.0

close
(
const scope: Scope.CloseableScope
scope
,
import Exit
Exit
.
const void: Exit.Exit<void, never>
export void

Represents an Exit which succeeds with undefined.

@since2.0.0

void
)
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("作用域已关闭")
// 即使作用域已关闭,此任务仍会执行
yield*
const task: Effect.Effect<void, never, Scope.Scope>
task
.
Pipeable.pipe<Effect.Effect<void, never, Scope.Scope>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, Scope.Scope>, ab: (_: Effect.Effect<void, never, Scope.Scope>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Scope
Scope
.
const extend: (scope: Scope.Scope) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope.Scope>> (+1 overload)

Extends the scope of an Effect that requires a scope into this scope. It provides this scope to the effect but does not close the scope when the effect completes execution. This allows extending a scoped value into a larger scope.

@since2.0.0

extend
(
const scope: Scope.CloseableScope
scope
))
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

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

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

When to Use

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

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const program: Effect.Effect<void, never, never>
program
)
/*
输出:
作用域已关闭
已执行 <-- 1秒后
任务终结器
*/

Effect.acquireRelease(acquire, release) 函数允许您定义在不再需要时获取和安全释放的资源。这对于管理文件句柄、数据库连接或网络套接字等资源非常有用。

要使用 Effect.acquireRelease,您需要定义两个操作:

  1. 获取资源:描述资源获取的 Effect,例如打开文件或建立数据库连接。
  2. 释放资源:确保资源正确释放的清理 Effect,例如关闭文件或连接。

获取过程是不可中断的,以确保部分资源获取不会使您的系统处于不一致状态。

Effect.acquireRelease 函数保证一旦资源成功获取,当 Scope 关闭时,其释放步骤总是会执行。

示例(定义简单资源)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// 定义资源的接口
interface
interface MyResource
MyResource
{
readonly
MyResource.contents: string
contents
: string
readonly
MyResource.close: () => Promise<void>
close
: () =>
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<void>
}
// 模拟资源获取
const
const getMyResource: () => Promise<MyResource>
getMyResource
= ():
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<
interface MyResource
MyResource
> =>
var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.
PromiseConstructor.resolve<{
contents: string;
close: () => Promise<void>;
}>(value: {
contents: string;
close: () => Promise<void>;
}): Promise<{
contents: string;
close: () => Promise<void>;
}> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.

@returnsA promise whose internal state matches the provided promise.

resolve
({
contents: string
contents
: "lorem ipsum",
close: () => Promise<void>
close
: () =>
new
var Promise: PromiseConstructor
new <void>(executor: (resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void) => void) => Promise<void>

Creates a new Promise.

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

Promise
((
resolve: (value: void | PromiseLike<void>) => void
resolve
) => {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("资源已释放")
resolve: (value: void | PromiseLike<void>) => void
resolve
()
})
})
// 定义如何获取资源
const
const acquire: Effect.Effect<MyResource, Error, never>
acquire
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tryPromise: <MyResource, Error>(options: {
readonly try: (signal: AbortSignal) => PromiseLike<MyResource>;
readonly catch: (error: unknown) => Error;
}) => Effect.Effect<MyResource, Error, never> (+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:

  1. If you don't provide a catch function, the error is caught and the effect fails with an UnknownException.
  2. 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<Response, UnknownException, never>
// ▼
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<Response, Error, never>
// ▼
const program = getTodo(1)

@seepromise if the effectful computation is asynchronous and does not throw errors.

@since2.0.0

tryPromise
({
try: (signal: AbortSignal) => PromiseLike<MyResource>
try
: () =>
const getMyResource: () => Promise<MyResource>
getMyResource
().
Promise<MyResource>.then<MyResource, never>(onfulfilled?: ((value: MyResource) => MyResource | PromiseLike<MyResource>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<MyResource>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
((
res: MyResource
res
) => {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("资源已获取")
return
res: MyResource
res
}),
catch: (error: unknown) => Error
catch
: () => new
var Error: ErrorConstructor
new (message?: string) => Error
Error
("getMyResourceError")
})
// 定义如何释放资源
const
const release: (res: MyResource) => Effect.Effect<void, never, never>
release
= (
res: MyResource
res
:
interface MyResource
MyResource
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

Details

The provided function (thunk) returns a Promise that should never reject; if it does, the error will be treated as a "defect".

This defect is not a standard error but indicates a flaw in the logic that was expected to be error-free. You can think of it similar to an unexpected crash in the program, which can be further managed or logged using tools like

catchAllDefect

.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

When to Use

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

Example (Delayed Message)

import { Effect } from "effect"
const delay = (message: string) =>
Effect.promise<string>(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve(message)
}, 2000)
})
)
// ┌─── Effect<string, never, never>
// ▼
const program = delay("Async operation completed successfully!")

@seetryPromise for a version that can handle failures.

@since2.0.0

promise
(() =>
res: MyResource
res
.
MyResource.close: () => Promise<void>
close
())
// 创建资源管理工作流
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const
const resource: Effect.Effect<MyResource, Error, Scope>
resource
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <MyResource, Error, never, void, never>(acquire: Effect.Effect<MyResource, Error, never>, release: (a: MyResource, exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<MyResource, Error, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const acquire: Effect.Effect<MyResource, Error, never>
acquire
,
const release: (res: MyResource) => Effect.Effect<void, never, never>
release
)

在上面的代码中,Effect.acquireRelease 函数创建了一个需要 Scope 的资源工作流:

const resource: Effect<MyResource, Error, Scope>

这意味着工作流需要一个 Scope 来运行,当作用域关闭时,资源将自动释放。

您现在可以通过使用 Effect.andThen 或类似函数链接操作来使用资源。

我们可以通过使用 Effect.andThen 或其他 Effect 操作符来继续使用资源,只要我们想要。例如,以下是我们如何读取内容:

示例(使用资源)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
32 collapsed lines
// Define an interface for a resource
interface
interface MyResource
MyResource
{
readonly
MyResource.contents: string
contents
: string
readonly
MyResource.close: () => Promise<void>
close
: () =>
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<void>
}
// Simulate resource acquisition
const
const getMyResource: () => Promise<MyResource>
getMyResource
= ():
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<
interface MyResource
MyResource
> =>
var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.
PromiseConstructor.resolve<{
contents: string;
close: () => Promise<void>;
}>(value: {
contents: string;
close: () => Promise<void>;
}): Promise<{
contents: string;
close: () => Promise<void>;
}> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.

@returnsA promise whose internal state matches the provided promise.

resolve
({
contents: string
contents
: "lorem ipsum",
close: () => Promise<void>
close
: () =>
new
var Promise: PromiseConstructor
new <void>(executor: (resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void) => void) => Promise<void>

Creates a new Promise.

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

Promise
((
resolve: (value: void | PromiseLike<void>) => void
resolve
) => {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Resource released")
resolve: (value: void | PromiseLike<void>) => void
resolve
()
})
})
// Define how the resource is acquired
const
const acquire: Effect.Effect<MyResource, Error, never>
acquire
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tryPromise: <MyResource, Error>(options: {
readonly try: (signal: AbortSignal) => PromiseLike<MyResource>;
readonly catch: (error: unknown) => Error;
}) => Effect.Effect<MyResource, Error, never> (+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:

  1. If you don't provide a catch function, the error is caught and the effect fails with an UnknownException.
  2. 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<Response, UnknownException, never>
// ▼
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<Response, Error, never>
// ▼
const program = getTodo(1)

@seepromise if the effectful computation is asynchronous and does not throw errors.

@since2.0.0

tryPromise
({
try: (signal: AbortSignal) => PromiseLike<MyResource>
try
: () =>
const getMyResource: () => Promise<MyResource>
getMyResource
().
Promise<MyResource>.then<MyResource, never>(onfulfilled?: ((value: MyResource) => MyResource | PromiseLike<MyResource>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<MyResource>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
((
res: MyResource
res
) => {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Resource acquired")
return
res: MyResource
res
}),
catch: (error: unknown) => Error
catch
: () => new
var Error: ErrorConstructor
new (message?: string) => Error
Error
("getMyResourceError")
})
// Define how the resource is released
const
const release: (res: MyResource) => Effect.Effect<void, never, never>
release
= (
res: MyResource
res
:
interface MyResource
MyResource
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

Details

The provided function (thunk) returns a Promise that should never reject; if it does, the error will be treated as a "defect".

This defect is not a standard error but indicates a flaw in the logic that was expected to be error-free. You can think of it similar to an unexpected crash in the program, which can be further managed or logged using tools like

catchAllDefect

.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

When to Use

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

Example (Delayed Message)

import { Effect } from "effect"
const delay = (message: string) =>
Effect.promise<string>(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve(message)
}, 2000)
})
)
// ┌─── Effect<string, never, never>
// ▼
const program = delay("Async operation completed successfully!")

@seetryPromise for a version that can handle failures.

@since2.0.0

promise
(() =>
res: MyResource
res
.
MyResource.close: () => Promise<void>
close
())
// Create the resource management workflow
const
const resource: Effect.Effect<MyResource, Error, Scope>
resource
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <MyResource, Error, never, void, never>(acquire: Effect.Effect<MyResource, Error, never>, release: (a: MyResource, exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<MyResource, Error, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const acquire: Effect.Effect<MyResource, Error, never>
acquire
,
const release: (res: MyResource) => Effect.Effect<void, never, never>
release
)
// ┌─── Effect<void, Error, Scope>
// ▼
const
const program: Effect.Effect<void, Error, Scope>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const res: MyResource
res
= yield*
const resource: Effect.Effect<MyResource, Error, Scope>
resource
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(`内容是 ${
const res: MyResource
res
.
MyResource.contents: string
contents
}`)
})

为了确保正确的资源管理,当您完成资源使用时应该关闭 ScopeEffect.scoped 函数通过创建一个 Scope、运行 Effect,然后在 Effect 完成时关闭 Scope 来为您处理这个问题。

示例(使用 Effect.scoped 提供 Scope

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
32 collapsed lines
// Define an interface for a resource
interface
interface MyResource
MyResource
{
readonly
MyResource.contents: string
contents
: string
readonly
MyResource.close: () => Promise<void>
close
: () =>
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<void>
}
// Simulate resource acquisition
const
const getMyResource: () => Promise<MyResource>
getMyResource
= ():
interface Promise<T>

Represents the completion of an asynchronous operation

Promise
<
interface MyResource
MyResource
> =>
var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.
PromiseConstructor.resolve<{
contents: string;
close: () => Promise<void>;
}>(value: {
contents: string;
close: () => Promise<void>;
}): Promise<{
contents: string;
close: () => Promise<void>;
}> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.

@returnsA promise whose internal state matches the provided promise.

resolve
({
contents: string
contents
: "lorem ipsum",
close: () => Promise<void>
close
: () =>
new
var Promise: PromiseConstructor
new <void>(executor: (resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void) => void) => Promise<void>

Creates a new Promise.

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

Promise
((
resolve: (value: void | PromiseLike<void>) => void
resolve
) => {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Resource released")
resolve: (value: void | PromiseLike<void>) => void
resolve
()
})
})
// Define how the resource is acquired
const
const acquire: Effect.Effect<MyResource, Error, never>
acquire
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tryPromise: <MyResource, Error>(options: {
readonly try: (signal: AbortSignal) => PromiseLike<MyResource>;
readonly catch: (error: unknown) => Error;
}) => Effect.Effect<MyResource, Error, never> (+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:

  1. If you don't provide a catch function, the error is caught and the effect fails with an UnknownException.
  2. 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<Response, UnknownException, never>
// ▼
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<Response, Error, never>
// ▼
const program = getTodo(1)

@seepromise if the effectful computation is asynchronous and does not throw errors.

@since2.0.0

tryPromise
({
try: (signal: AbortSignal) => PromiseLike<MyResource>
try
: () =>
const getMyResource: () => Promise<MyResource>
getMyResource
().
Promise<MyResource>.then<MyResource, never>(onfulfilled?: ((value: MyResource) => MyResource | PromiseLike<MyResource>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<MyResource>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
((
res: MyResource
res
) => {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Resource acquired")
return
res: MyResource
res
}),
catch: (error: unknown) => Error
catch
: () => new
var Error: ErrorConstructor
new (message?: string) => Error
Error
("getMyResourceError")
})
// Define how the resource is released
const
const release: (res: MyResource) => Effect.Effect<void, never, never>
release
= (
res: MyResource
res
:
interface MyResource
MyResource
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

Details

The provided function (thunk) returns a Promise that should never reject; if it does, the error will be treated as a "defect".

This defect is not a standard error but indicates a flaw in the logic that was expected to be error-free. You can think of it similar to an unexpected crash in the program, which can be further managed or logged using tools like

catchAllDefect

.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

When to Use

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

Example (Delayed Message)

import { Effect } from "effect"
const delay = (message: string) =>
Effect.promise<string>(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve(message)
}, 2000)
})
)
// ┌─── Effect<string, never, never>
// ▼
const program = delay("Async operation completed successfully!")

@seetryPromise for a version that can handle failures.

@since2.0.0

promise
(() =>
res: MyResource
res
.
MyResource.close: () => Promise<void>
close
())
// Create the resource management workflow
const
const resource: Effect.Effect<MyResource, Error, Scope>
resource
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <MyResource, Error, never, void, never>(acquire: Effect.Effect<MyResource, Error, never>, release: (a: MyResource, exit: Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<MyResource, Error, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const acquire: Effect.Effect<MyResource, Error, never>
acquire
,
const release: (res: MyResource) => Effect.Effect<void, never, never>
release
)
// ┌─── Effect<void, Error, never>
// ▼
const
const program: Effect.Effect<void, Error, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <void, Error, Scope>(effect: Effect.Effect<void, Error, Scope>) => Effect.Effect<void, Error, never>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const res: MyResource
res
= yield*
const resource: Effect.Effect<MyResource, Error, Scope>
resource
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(`内容是 ${
const res: MyResource
res
.
MyResource.contents: string
contents
}`)
})
)
// 我们现在有一个准备运行的工作流
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

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

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

When to Use

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

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const program: Effect.Effect<void, Error, never>
program
)
/*
资源已获取
内容是 lorem ipsum
资源已释放
*/

在某些场景中,您可能需要执行一系列链式操作,其中每个操作的成功都依赖于前一个操作。但是,如果任何操作失败,您希望撤销所有先前成功操作的效果。当您需要确保要么所有操作都成功,要么都没有任何效果时,这种模式非常有价值。

让我们通过一个实现此模式的示例。假设我们想在应用程序中创建一个”工作空间”,这涉及创建一个 S3 存储桶、一个 ElasticSearch 索引和一个依赖于前两者的数据库条目。

首先,我们为所需的服务定义域模型:

  • S3
  • ElasticSearch
  • Database
import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Data
Data
} from "effect"
class
class S3Error
S3Error
extends
import Data
Data
.
const TaggedError: <"S3Error">(tag: "S3Error") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "S3Error";
} & Readonly<A>

@since2.0.0

TaggedError
("S3Error")<{}> {}
interface
interface Bucket
Bucket
{
readonly
Bucket.name: string
name
: string
}
class
class S3
S3
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("S3")<
class S3
S3
,
{
readonly
createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Bucket
Bucket
,
class S3Error
S3Error
>
readonly
deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket
: (
bucket: Bucket
bucket
:
interface Bucket
Bucket
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
class
class ElasticSearchError
ElasticSearchError
extends
import Data
Data
.
const TaggedError: <"ElasticSearchError">(tag: "ElasticSearchError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "ElasticSearchError";
} & Readonly<A>

@since2.0.0

TaggedError
(
"ElasticSearchError"
)<{}> {}
interface
interface Index
Index
{
readonly
Index.id: string
id
: string
}
class
class ElasticSearch
ElasticSearch
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("ElasticSearch")<
class ElasticSearch
ElasticSearch
,
{
readonly
createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Index
Index
,
class ElasticSearchError
ElasticSearchError
>
readonly
deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex
: (
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
class
class DatabaseError
DatabaseError
extends
import Data
Data
.
const TaggedError: <"DatabaseError">(tag: "DatabaseError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "DatabaseError";
} & Readonly<A>

@since2.0.0

TaggedError
("DatabaseError")<{}> {}
interface
interface Entry
Entry
{
readonly
Entry.id: string
id
: string
}
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{
readonly
createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry
: (
bucket: Bucket
bucket
:
interface Bucket
Bucket
,
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Entry
Entry
,
class DatabaseError
DatabaseError
>
readonly
deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry
: (
entry: Entry
entry
:
interface Entry
Entry
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}

接下来,我们为工作空间定义三个创建操作和整体事务(make)。

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Exit
Exit
,
import Data
Data
} from "effect"
46 collapsed lines
class
class S3Error
S3Error
extends
import Data
Data
.
const TaggedError: <"S3Error">(tag: "S3Error") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "S3Error";
} & Readonly<A>

@since2.0.0

TaggedError
("S3Error")<{}> {}
interface
interface Bucket
Bucket
{
readonly
Bucket.name: string
name
: string
}
class
class S3
S3
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("S3")<
class S3
S3
,
{
readonly
createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Bucket
Bucket
,
class S3Error
S3Error
>
readonly
deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket
: (
bucket: Bucket
bucket
:
interface Bucket
Bucket
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
class
class ElasticSearchError
ElasticSearchError
extends
import Data
Data
.
const TaggedError: <"ElasticSearchError">(tag: "ElasticSearchError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "ElasticSearchError";
} & Readonly<A>

@since2.0.0

TaggedError
(
"ElasticSearchError"
)<{}> {}
interface
interface Index
Index
{
readonly
Index.id: string
id
: string
}
class
class ElasticSearch
ElasticSearch
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("ElasticSearch")<
class ElasticSearch
ElasticSearch
,
{
readonly
createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Index
Index
,
class ElasticSearchError
ElasticSearchError
>
readonly
deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex
: (
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
class
class DatabaseError
DatabaseError
extends
import Data
Data
.
const TaggedError: <"DatabaseError">(tag: "DatabaseError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "DatabaseError";
} & Readonly<A>

@since2.0.0

TaggedError
("DatabaseError")<{}> {}
interface
interface Entry
Entry
{
readonly
Entry.id: string
id
: string
}
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{
readonly
createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry
: (
bucket: Bucket
bucket
:
interface Bucket
Bucket
,
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Entry
Entry
,
class DatabaseError
DatabaseError
>
readonly
deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry
: (
entry: Entry
entry
:
interface Entry
Entry
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
// 创建存储桶,并定义在操作失败时删除存储桶的释放函数
const
const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Bucket, S3Error, Scope>>, Bucket>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Bucket, S3Error, Scope>>, Bucket, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const {
const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket
,
const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket
} = yield*
class S3
S3
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <Bucket, S3Error, never, void, never>(acquire: Effect.Effect<Bucket, S3Error, never>, release: (a: Bucket, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<Bucket, S3Error, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket
, (
bucket: Bucket
bucket
,
exit: Exit.Exit<unknown, unknown>
exit
) =>
// Effect.acquireRelease 操作的释放函数负责在主 Effect 完成后
// 处理获取的资源(存储桶)。无论主 Effect 成功还是失败,
// 都会调用此函数。如果主 Effect 失败,Exit.isFailure(exit)
// 将为 true,函数将通过调用 deleteBucket(bucket) 执行回滚。
// 如果主 Effect 成功,Exit.isFailure(exit) 将为 false,
// 函数将返回 Effect.void,表示成功但无操作的 Effect。
import Exit
Exit
.
const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>

Returns true if the specified Exit is a Failure, false otherwise.

@since2.0.0

isFailure
(
exit: Exit.Exit<unknown, unknown>
exit
) ?
const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket
(
bucket: Bucket
bucket
) :
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents 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.

@since2.0.0

void
)
})
// 创建索引,并定义在操作失败时删除索引的释放函数
const
const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Index, ElasticSearchError, Scope>>, Index>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}>> | YieldWrap<...>, Index, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const {
const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex
,
const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex
} = yield*
class ElasticSearch
ElasticSearch
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <Index, ElasticSearchError, never, void, never>(acquire: Effect.Effect<Index, ElasticSearchError, never>, release: (a: Index, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<Index, ElasticSearchError, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex
, (
index: Index
index
,
exit: Exit.Exit<unknown, unknown>
exit
) =>
import Exit
Exit
.
const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>

Returns true if the specified Exit is a Failure, false otherwise.

@since2.0.0

isFailure
(
exit: Exit.Exit<unknown, unknown>
exit
) ?
const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex
(
index: Index
index
) :
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents 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.

@since2.0.0

void
)
})
// 在数据库中创建条目,并定义在操作失败时删除条目的释放函数
const
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry
= (
bucket: Bucket
bucket
:
interface Bucket
Bucket
,
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Entry, DatabaseError, Scope>>, Entry>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}>> | YieldWrap<...>, Entry, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const {
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry
,
const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry
} = yield*
class Database
Database
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <Entry, DatabaseError, never, void, never>(acquire: Effect.Effect<Entry, DatabaseError, never>, release: (a: Entry, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<Entry, DatabaseError, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry
(
bucket: Bucket
bucket
,
index: Index
index
),
(
entry: Entry
entry
,
exit: Exit.Exit<unknown, unknown>
exit
) =>
import Exit
Exit
.
const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>

Returns true if the specified Exit is a Failure, false otherwise.

@since2.0.0

isFailure
(
exit: Exit.Exit<unknown, unknown>
exit
) ?
const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry
(
entry: Entry
entry
) :
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents 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.

@since2.0.0

void
)
})
const
const make: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>
make
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database | Scope>(effect: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database | Scope>) => Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<Bucket, S3Error, S3 | Scope>> | YieldWrap<Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>> | YieldWrap<Effect.Effect<Entry, DatabaseError, Database | Scope>>, Entry>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<Bucket, S3Error, S3 | Scope>> | YieldWrap<...> | YieldWrap<...>, Entry, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const bucket: Bucket
bucket
= yield*
const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket
const
const index: Index
index
= yield*
const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex
return yield*
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry
(
const bucket: Bucket
bucket
,
const index: Index
index
)
})
)

然后我们创建简单的服务实现来测试我们的工作空间代码的行为。 为了实现这一点,我们将利用来构建测试。 这些层将能够处理各种场景,包括错误,我们可以使用 FailureCase 类型来控制这些错误。

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Exit
Exit
,
import Data
Data
,
import Layer
Layer
,
import Console
Console
} from "effect"
93 collapsed lines
class
class S3Error
S3Error
extends
import Data
Data
.
const TaggedError: <"S3Error">(tag: "S3Error") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "S3Error";
} & Readonly<A>

@since2.0.0

TaggedError
("S3Error")<{}> {}
interface
interface Bucket
Bucket
{
readonly
Bucket.name: string
name
: string
}
class
class S3
S3
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("S3")<
class S3
S3
,
{
readonly
createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Bucket
Bucket
,
class S3Error
S3Error
>
readonly
deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket
: (
bucket: Bucket
bucket
:
interface Bucket
Bucket
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
class
class ElasticSearchError
ElasticSearchError
extends
import Data
Data
.
const TaggedError: <"ElasticSearchError">(tag: "ElasticSearchError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "ElasticSearchError";
} & Readonly<A>

@since2.0.0

TaggedError
(
"ElasticSearchError"
)<{}> {}
interface
interface Index
Index
{
readonly
Index.id: string
id
: string
}
class
class ElasticSearch
ElasticSearch
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("ElasticSearch")<
class ElasticSearch
ElasticSearch
,
{
readonly
createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Index
Index
,
class ElasticSearchError
ElasticSearchError
>
readonly
deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex
: (
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
class
class DatabaseError
DatabaseError
extends
import Data
Data
.
const TaggedError: <"DatabaseError">(tag: "DatabaseError") => new <A>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
readonly _tag: "DatabaseError";
} & Readonly<A>

@since2.0.0

TaggedError
("DatabaseError")<{}> {}
interface
interface Entry
Entry
{
readonly
Entry.id: string
id
: string
}
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{
readonly
createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry
: (
bucket: Bucket
bucket
:
interface Bucket
Bucket
,
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<
interface Entry
Entry
,
class DatabaseError
DatabaseError
>
readonly
deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry
: (
entry: Entry
entry
:
interface Entry
Entry
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

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

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

@since2.0.0

@since2.0.0

Effect
<void>
}
>() {}
// Create a bucket, and define the release function that deletes the
// bucket if the operation fails.
const
const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Bucket, S3Error, Scope>>, Bucket>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Bucket, S3Error, Scope>>, Bucket, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const {
const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket
,
const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket
} = yield*
class S3
S3
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <Bucket, S3Error, never, void, never>(acquire: Effect.Effect<Bucket, S3Error, never>, release: (a: Bucket, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<Bucket, S3Error, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const createBucket: Effect.Effect<Bucket, S3Error, never>
createBucket
, (
bucket: Bucket
bucket
,
exit: Exit.Exit<unknown, unknown>
exit
) =>
// The release function for the Effect.acquireRelease operation is
// responsible for handling the acquired resource (bucket) after the
// main effect has completed. It is called regardless of whether the
// main effect succeeded or failed. If the main effect failed,
// Exit.isFailure(exit) will be true, and the function will perform
// a rollback by calling deleteBucket(bucket). If the main effect
// succeeded, Exit.isFailure(exit) will be false, and the function
// will return Effect.void, representing a successful, but
// do-nothing effect.
import Exit
Exit
.
const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>

Returns true if the specified Exit is a Failure, false otherwise.

@since2.0.0

isFailure
(
exit: Exit.Exit<unknown, unknown>
exit
) ?
const deleteBucket: (bucket: Bucket) => Effect.Effect<void>
deleteBucket
(
bucket: Bucket
bucket
) :
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents 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.

@since2.0.0

void
)
})
// Create an index, and define the release function that deletes the
// index if the operation fails.
const
const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Index, ElasticSearchError, Scope>>, Index>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}>> | YieldWrap<...>, Index, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const {
const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex
,
const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex
} = yield*
class ElasticSearch
ElasticSearch
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <Index, ElasticSearchError, never, void, never>(acquire: Effect.Effect<Index, ElasticSearchError, never>, release: (a: Index, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<Index, ElasticSearchError, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const createIndex: Effect.Effect<Index, ElasticSearchError, never>
createIndex
, (
index: Index
index
,
exit: Exit.Exit<unknown, unknown>
exit
) =>
import Exit
Exit
.
const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>

Returns true if the specified Exit is a Failure, false otherwise.

@since2.0.0

isFailure
(
exit: Exit.Exit<unknown, unknown>
exit
) ?
const deleteIndex: (index: Index) => Effect.Effect<void>
deleteIndex
(
index: Index
index
) :
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents 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.

@since2.0.0

void
)
})
// Create an entry in the database, and define the release function that
// deletes the entry if the operation fails.
const
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry
= (
bucket: Bucket
bucket
:
interface Bucket
Bucket
,
index: Index
index
:
interface Index
Index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}>> | YieldWrap<Effect.Effect<Entry, DatabaseError, Scope>>, Entry>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}>> | YieldWrap<...>, Entry, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const {
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry
,
const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry
} = yield*
class Database
Database
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const acquireRelease: <Entry, DatabaseError, never, void, never>(acquire: Effect.Effect<Entry, DatabaseError, never>, release: (a: Entry, exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, never>) => Effect.Effect<Entry, DatabaseError, Scope> (+1 overload)

Creates a scoped resource using an acquire and release effect.

Details

This function helps manage resources by combining two Effect values: one for acquiring the resource and one for releasing it.

acquireRelease does the following:

  1. Ensures that the effect that acquires the resource will not be interrupted. Note that acquisition may still fail due to internal reasons (such as an uncaught exception).
  2. Ensures that the release effect will not be interrupted, and will be executed as long as the acquisition effect successfully acquires the resource.

If the acquire function succeeds, the release function is added to the list of finalizers for the scope. This ensures that the release will happen automatically when the scope is closed.

Both acquire and release run uninterruptibly, meaning they cannot be interrupted while they are executing.

Additionally, the release function can be influenced by the exit value when the scope closes, allowing for custom handling of how the resource is released based on the execution outcome.

When to Use

This function is used to ensure that an effect that represents the acquisition of a resource (for example, opening a file, launching a thread, etc.) will not be interrupted, and that the resource will always be released when the Effect completes execution.

Example (Defining a Simple Resource)

import { Effect } from "effect"
// Define an interface for a resource
interface MyResource {
readonly contents: string
readonly close: () => Promise<void>
}
// Simulate resource acquisition
const getMyResource = (): Promise<MyResource> =>
Promise.resolve({
contents: "lorem ipsum",
close: () =>
new Promise((resolve) => {
console.log("Resource released")
resolve()
})
})
// Define how the resource is acquired
const acquire = Effect.tryPromise({
try: () =>
getMyResource().then((res) => {
console.log("Resource acquired")
return res
}),
catch: () => new Error("getMyResourceError")
})
// Define how the resource is released
const release = (res: MyResource) => Effect.promise(() => res.close())
// Create the resource management workflow
//
// ┌─── Effect<MyResource, Error, Scope>
// ▼
const resource = Effect.acquireRelease(acquire, release)

@seeacquireUseRelease for a version that automatically handles the scoping of resources.

@since2.0.0

acquireRelease
(
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>
createEntry
(
bucket: Bucket
bucket
,
index: Index
index
),
(
entry: Entry
entry
,
exit: Exit.Exit<unknown, unknown>
exit
) =>
import Exit
Exit
.
const isFailure: <unknown, unknown>(self: Exit.Exit<unknown, unknown>) => self is Exit.Failure<unknown, unknown>

Returns true if the specified Exit is a Failure, false otherwise.

@since2.0.0

isFailure
(
exit: Exit.Exit<unknown, unknown>
exit
) ?
const deleteEntry: (entry: Entry) => Effect.Effect<void>
deleteEntry
(
entry: Entry
entry
) :
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents 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.

@since2.0.0

void
)
})
const
const make: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>
make
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database | Scope>(effect: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database | Scope>) => Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<Bucket, S3Error, S3 | Scope>> | YieldWrap<Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>> | YieldWrap<Effect.Effect<Entry, DatabaseError, Database | Scope>>, Entry>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<Bucket, S3Error, S3 | Scope>> | YieldWrap<...> | YieldWrap<...>, Entry, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const bucket: Bucket
bucket
= yield*
const createBucket: Effect.Effect<Bucket, S3Error, S3 | Scope>
createBucket
const
const index: Index
index
= yield*
const createIndex: Effect.Effect<Index, ElasticSearchError, ElasticSearch | Scope>
createIndex
return yield*
const createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError, Database | Scope>
createEntry
(
const bucket: Bucket
bucket
,
const index: Index
index
)
})
)
// The `FailureCaseLiterals` type allows us to provide different error
// scenarios while testing our
//
// For example, by providing the value "S3", we can simulate an error
// scenario specific to the S3 service. This helps us ensure that our
// program handles errors correctly and behaves as expected in various
// situations.
//
// Similarly, we can provide other values like "ElasticSearch" or
// "Database" to simulate error scenarios for those In cases
// where we want to test the absence of errors, we can provide
// `undefined`. By using this parameter, we can thoroughly test our
// services and verify their behavior under different error conditions.
type
type FailureCaseLiterals = "S3" | "ElasticSearch" | "Database" | undefined
FailureCaseLiterals
= "S3" | "ElasticSearch" | "Database" | undefined
class
class FailureCase
FailureCase
extends
import Context

@since2.0.0

@since2.0.0

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

@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 })
}

@since2.0.0

Tag
("FailureCase")<
class FailureCase
FailureCase
,
type FailureCaseLiterals = "S3" | "ElasticSearch" | "Database" | undefined
FailureCaseLiterals
>() {}
// Create a test layer for the S3 service
const
const S3Test: Layer.Layer<S3, never, FailureCase>
S3Test
=
import Layer
Layer
.
const effect: <S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}, never, FailureCase>(tag: Context.Tag<S3, {
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}>, effect: Effect.Effect<{
readonly createBucket: Effect.Effect<Bucket, S3Error>;
readonly deleteBucket: (bucket: Bucket) => Effect.Effect<void>;
}, never, FailureCase>) => Layer.Layer<S3, never, FailureCase> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class S3
S3
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createBucket: Effect.Effect<{
name: string;
}, S3Error, never>;
deleteBucket: (bucket: Bucket) => Effect.Effect<void, never, never>;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createBucket: Effect.Effect<{
name: string;
}, S3Error, never>;
deleteBucket: (bucket: Bucket) => Effect.Effect<void, never, never>;
}, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const failureCase: FailureCaseLiterals
failureCase
= yield*
class FailureCase
FailureCase
return {
createBucket: Effect.Effect<{
name: string;
}, S3Error, never>
createBucket
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<never, S3Error, never>>, {
name: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<never, S3Error, never>>, {
name: string;
}, never>) => Effect.Effect<{
name: string;
}, S3Error, never> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("[S3] creating bucket")
if (
const failureCase: FailureCaseLiterals
failureCase
=== "S3") {
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <S3Error>(error: S3Error) => Effect.Effect<never, S3Error, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

Example (Creating a Failed Effect)

import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@seesucceed to create an effect that represents a successful value.

@since2.0.0

fail
(new
constructor S3Error<{}>(args: void): S3Error
S3Error
())
} else {
return {
name: string
name
: "<bucket.name>" }
}
}),
deleteBucket: (bucket: Bucket) => Effect.Effect<void, never, never>
deleteBucket
: (
bucket: Bucket
bucket
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`[S3] delete bucket ${
bucket: Bucket
bucket
.
Bucket.name: string
name
}`)
}
})
)
// Create a test layer for the ElasticSearch service
const
const ElasticSearchTest: Layer.Layer<ElasticSearch, never, FailureCase>
ElasticSearchTest
=
import Layer
Layer
.
const effect: <ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}, never, FailureCase>(tag: Context.Tag<ElasticSearch, {
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}>, effect: Effect.Effect<{
readonly createIndex: Effect.Effect<Index, ElasticSearchError>;
readonly deleteIndex: (index: Index) => Effect.Effect<void>;
}, never, FailureCase>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class ElasticSearch
ElasticSearch
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createIndex: Effect.Effect<{
id: string;
}, ElasticSearchError, never>;
deleteIndex: (index: Index) => Effect.Effect<void, never, never>;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createIndex: Effect.Effect<{
id: string;
}, ElasticSearchError, never>;
deleteIndex: (index: Index) => Effect.Effect<void, never, never>;
}, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const failureCase: FailureCaseLiterals
failureCase
= yield*
class FailureCase
FailureCase
return {
createIndex: Effect.Effect<{
id: string;
}, ElasticSearchError, never>
createIndex
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<never, ElasticSearchError, never>>, {
id: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<never, ElasticSearchError, never>>, {
id: string;
}, never>) => Effect.Effect<{
id: string;
}, ElasticSearchError, never> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("[ElasticSearch] creating index")
if (
const failureCase: FailureCaseLiterals
failureCase
=== "ElasticSearch") {
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <ElasticSearchError>(error: ElasticSearchError) => Effect.Effect<never, ElasticSearchError, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

Example (Creating a Failed Effect)

import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@seesucceed to create an effect that represents a successful value.

@since2.0.0

fail
(new
constructor ElasticSearchError<{}>(args: void): ElasticSearchError
ElasticSearchError
())
} else {
return {
id: string
id
: "<index.id>" }
}
}),
deleteIndex: (index: Index) => Effect.Effect<void, never, never>
deleteIndex
: (
index: Index
index
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`[ElasticSearch] delete index ${
index: Index
index
.
Index.id: string
id
}`)
}
})
)
// Create a test layer for the Database service
const
const DatabaseTest: Layer.Layer<Database, never, FailureCase>
DatabaseTest
=
import Layer
Layer
.
const effect: <Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}, never, FailureCase>(tag: Context.Tag<Database, {
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}>, effect: Effect.Effect<{
readonly createEntry: (bucket: Bucket, index: Index) => Effect.Effect<Entry, DatabaseError>;
readonly deleteEntry: (entry: Entry) => Effect.Effect<void>;
}, never, FailureCase>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Database
Database
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createEntry: (bucket: Bucket, index: Index) => Effect.Effect<{
id: string;
}, DatabaseError, never>;
deleteEntry: (entry: Entry) => Effect.Effect<void, never, never>;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<FailureCase, FailureCaseLiterals>>, {
createEntry: (bucket: Bucket, index: Index) => Effect.Effect<{
id: string;
}, DatabaseError, never>;
deleteEntry: (entry: Entry) => Effect.Effect<void, never, never>;
}, never>) => Effect.Effect<...> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const failureCase: FailureCaseLiterals
failureCase
= yield*
class FailureCase
FailureCase
return {
createEntry: (bucket: Bucket, index: Index) => Effect.Effect<{
id: string;
}, DatabaseError, never>
createEntry
: (
bucket: Bucket
bucket
,
index: Index
index
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<never, DatabaseError, never>>, {
id: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<never, DatabaseError, never>>, {
id: string;
}, never>) => Effect.Effect<{
id: string;
}, DatabaseError, never> (+1 overload)

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

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
"[Database] creating entry for bucket" +
`${
bucket: Bucket
bucket
.
Bucket.name: string
name
} and index ${
index: Index
index
.
Index.id: string
id
}`
)
if (
const failureCase: FailureCaseLiterals
failureCase
=== "Database") {
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <DatabaseError>(error: DatabaseError) => Effect.Effect<never, DatabaseError, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

Example (Creating a Failed Effect)

import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@seesucceed to create an effect that represents a successful value.

@since2.0.0

fail
(new
constructor DatabaseError<{}>(args: void): DatabaseError
DatabaseError
())
} else {
return {
id: string
id
: "<entry.id>" }
}
}),
deleteEntry: (entry: Entry) => Effect.Effect<void, never, never>
deleteEntry
: (
entry: Entry
entry
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`[Database] delete entry ${
entry: Entry
entry
.
Entry.id: string
id
}`)
}
})
)
// Merge all the test layers for S3, ElasticSearch, and Database
// services into a single layer
const
const layer: Layer.Layer<S3 | ElasticSearch | Database, never, FailureCase>
layer
=
import Layer
Layer
.
const mergeAll: <[Layer.Layer<S3, never, FailureCase>, Layer.Layer<ElasticSearch, never, FailureCase>, Layer.Layer<Database, never, FailureCase>]>(layers_0: Layer.Layer<S3, never, FailureCase>, layers_1: Layer.Layer<ElasticSearch, never, FailureCase>, layers_2: Layer.Layer<Database, never, FailureCase>) => Layer.Layer<S3 | ElasticSearch | Database, never, FailureCase>

Combines all the provided layers concurrently, creating a new layer with merged input, error, and output types.

@since2.0.0

mergeAll
(
const S3Test: Layer.Layer<S3, never, FailureCase>
S3Test
,
const ElasticSearchTest: Layer.Layer<ElasticSearch, never, FailureCase>
ElasticSearchTest
,
const DatabaseTest: Layer.Layer<Database, never, FailureCase>
DatabaseTest
)
// Create a runnable effect to test the Workspace code. The effect is
// provided with the test layer and a FailureCase service with undefined
// value (no failure case).
const
const runnable: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, never>
runnable
=
const make: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>
make
.
Pipeable.pipe<Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ElasticSearch | Database>, Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, FailureCase>, Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, S3 | ... 1 more ... | Database>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <S3 | ElasticSearch | Database, never, FailureCase>(layer: Layer.Layer<S3 | ElasticSearch | Database, never, FailureCase>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, FailureCase | Exclude<R, S3 | ElasticSearch | Database>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
const layer: Layer.Layer<S3 | ElasticSearch | Database, never, FailureCase>
layer
),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provideService: <FailureCase, FailureCaseLiterals>(tag: Context.Tag<FailureCase, FailureCaseLiterals>, service: FailureCaseLiterals) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, FailureCase>> (+1 overload)

Provides an implementation for a service in the context of an effect.

Details

This function allows you to supply a specific implementation for a service required by an effect. Services are typically defined using Context.Tag, which acts as a unique identifier for the service. By using this function, you link the service to its concrete implementation, enabling the effect to execute successfully without additional requirements.

For example, you can use this function to provide a random number generator, a logger, or any other service your effect depends on. Once the service is provided, all parts of the effect that rely on the service will automatically use the implementation you supplied.

Example

import { Effect, Context } from "effect"
// Declaring a tag for a service that generates random numbers
class Random extends Context.Tag("MyRandomService")<
Random,
{ readonly next: Effect.Effect<number> }
>() {}
// Using the service
const program = Effect.gen(function* () {
const random = yield* Random
const randomNumber = yield* random.next
console.log(`random number: ${randomNumber}`)
})
// Providing the implementation
//
// ┌─── Effect<void, never, never>
// ▼
const runnable = Effect.provideService(program, Random, {
next: Effect.sync(() => Math.random())
})
// Run successfully
Effect.runPromise(runnable)
// Example Output:
// random number: 0.8241872233134417

@seeprovide for providing multiple layers to an effect.

@since2.0.0

provideService
(
class FailureCase
FailureCase
,
var undefined
undefined
)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

Details

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

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

When to Use

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

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

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const either: <Entry, S3Error | ElasticSearchError | DatabaseError, never>(self: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, never>) => Effect.Effect<Either<Entry, S3Error | ElasticSearchError | DatabaseError>, never, never>

Encapsulates both success and failure of an Effect into an Either type.

Details

This function converts an effect that may fail into an effect that always succeeds, wrapping the outcome in an Either type. The result will be Either.Left if the effect fails, containing the recoverable error, or Either.Right if it succeeds, containing the result.

Using this function, you can handle recoverable errors explicitly without causing the effect to fail. This is particularly useful in scenarios where you want to chain effects and manage both success and failure in the same logical flow.

It's important to note that unrecoverable errors, often referred to as "defects," are still thrown and not captured within the Either type. Only failures that are explicitly represented as recoverable errors in the effect are encapsulated.

The resulting effect cannot fail directly because all recoverable failures are represented inside the Either type.

Example

import { Effect, Either, Random } from "effect"
class HttpError {
readonly _tag = "HttpError"
}
class ValidationError {
readonly _tag = "ValidationError"
}
// ┌─── Effect<string, HttpError | ValidationError, never>
// ▼
const program = Effect.gen(function* () {
const n1 = yield* Random.next
const n2 = yield* Random.next
if (n1 < 0.5) {
yield* Effect.fail(new HttpError())
}
if (n2 < 0.5) {
yield* Effect.fail(new ValidationError())
}
return "some result"
})
// ┌─── Effect<string, never, never>
// ▼
const recovered = Effect.gen(function* () {
// ┌─── Either<string, HttpError | ValidationError>
// ▼
const failureOrSuccess = yield* Effect.either(program)
return Either.match(failureOrSuccess, {
onLeft: (error) => `Recovering from ${error._tag}`,
onRight: (value) => value // Do nothing in case of success
})
})

@seeoption for a version that uses Option instead.

@seeexit for a version that encapsulates both recoverable errors and defects in an Exit.

@since2.0.0

either
(
const runnable: Effect.Effect<Entry, S3Error | ElasticSearchError | DatabaseError, never>
runnable
)).
Promise<Either<Entry, S3Error | ElasticSearchError | DatabaseError>>.then<void, never>(onfulfilled?: ((value: Either<Entry, S3Error | ElasticSearchError | DatabaseError>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<void>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
(
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
)

Let’s examine the test results for the scenario where FailureCase is set to undefined (happy path):

Terminal window
[S3] creating bucket
[ElasticSearch] creating index
[Database] creating entry for bucket <bucket.name> and index <index.id>
{ _id: 'Either', _tag: 'Right', right: { id: '<entry.id>' } }

In this case, all operations succeed, and we see a successful result with right({ id: '<entry.id>' }).

Now, let’s simulate a failure in the Database:

const runnable = make.pipe(
Effect.provide(layer),
Effect.provideService(FailureCase, "Database")
)

The console output will be:

Terminal window
[S3] creating bucket
[ElasticSearch] creating index
[Database] creating entry for bucket <bucket.name> and index <index.id>
[ElasticSearch] delete index <index.id>
[S3] delete bucket <bucket.name>
{ _id: 'Either', _tag: 'Left', left: { _tag: 'DatabaseError' } }

You can observe that once the Database error occurs, there is a complete rollback that deletes the ElasticSearch index first and then the associated S3 bucket. The result is a failure with left(new DatabaseError()).

Let’s now make the index creation fail instead:

const runnable = make.pipe(
Effect.provide(layer),
Effect.provideService(FailureCase, "ElasticSearch")
)

In this case, the console output will be:

Terminal window
[S3] creating bucket
[ElasticSearch] creating index
[S3] delete bucket <bucket.name>
{ _id: 'Either', _tag: 'Left', left: { _tag: 'ElasticSearchError' } }

As expected, once the ElasticSearch index creation fails, there is a rollback that deletes the S3 bucket. The result is a failure with left(new ElasticSearchError()).