Managing Layers
In the Managing Services page, you learned how to create effects which depend on some service to be provided in order to execute, as well as how to provide that service to an effect.
However, what if we have a service within our effect program that has dependencies on other services in order to be built? We want to avoid leaking these implementation details into the service interface.
To represent the “dependency graph” of our program and manage these dependencies more effectively, we can utilize a powerful abstraction called “Layer”.
Layers act as constructors for creating services, allowing us to manage dependencies during construction rather than at the service level. This approach helps to keep our service interfaces clean and focused.
Let’s review some key concepts before diving into the details:
Concept | Description |
---|---|
service | A reusable component providing specific functionality, used across different parts of an application. |
tag | A unique identifier representing a service, allowing Effect to locate and use it. |
context | A collection storing services, functioning like a map with tags as keys and services as values. |
layer | An abstraction for constructing services, managing dependencies during construction rather than at the service level. |
Let’s imagine that we are building a web application. We could imagine that the dependency graph for an application where we need to manage configuration, logging, and database access might look something like this:
- The
Config
service provides application configuration. - The
Logger
service depends on theConfig
service. - The
Database
service depends on both theConfig
andLogger
services.
Our goal is to build the Database
service along with its direct and indirect dependencies. This means we need to ensure that the Config
service is available for both Logger
and Database
, and then provide these dependencies to the Database
service.
We will use layers to construct the Database
service instead of providing a service implementation directly as we did in the Managing Services page.
The Layer
type is structured as follows:
┌─── The service to be created │ ┌─── The possible error │ │ ┌─── The required dependencies ▼ ▼ ▼Layer<RequirementsOut, Error, RequirementsIn>
A Layer
represents a blueprint for constructing a RequirementsOut
(the service). It requires a RequirementsIn
(dependencies) as input and may result in an error of type Error
during the construction process.
Parameter | Description |
---|---|
RequirementsOut | The service or resource to be created. |
Error | The type of error that might occur during the construction of the service. |
RequirementsIn | The dependencies required to construct the service. |
By using layers, you can better organize your services, ensuring that their dependencies are clearly defined and separated from their implementation details.
For simplicity, let’s assume that we won’t encounter any errors during the value construction (meaning Error = never
).
Now, let’s determine how many layers we need to implement our dependency graph:
Layer | Dependencies | Type |
---|---|---|
ConfigLive | The Config service does not depend on any other services | Layer<Config> |
LoggerLive | The Logger service depends on the Config service | Layer<Logger, never, Config> |
DatabaseLive | The Database service depends on Config and Logger | Layer<Database, never, Config | Logger> |
When a service has multiple dependencies, they are represented as a union type. In our case, the Database
service depends on both the Config
and Logger
services. Therefore, the type for the DatabaseLive
layer will be:
Layer<Database, never, Config | Logger>
The Config
service does not depend on any other services, so ConfigLive
will be the simplest layer to implement. Just like in the Managing Services page, we must create a tag for the service. And because the service has no dependencies, we can create the layer directly using the Layer.succeed
constructor:
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3// Declaring a tag for the Config service4class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<5 class Config
Config,6 {7 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{8 readonly (property) logLevel: string
logLevel: string9 readonly (property) connection: string
connection: string10 }>11 }12>() {}13
14// Layer<Config, never, never>15const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(16 class Config
Config,17 class Config
Config.(method) Tag<Config, { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }>.of(self: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}): {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
of({18 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({19 (property) logLevel: string
logLevel: "INFO",20 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"21 })22 })23)
Looking at the type of ConfigLive
we can observe:
RequirementsOut
isConfig
, indicating that constructing the layer will produce aConfig
serviceError
isnever
, indicating that layer construction cannot failRequirementsIn
isnever
, indicating that the layer has no dependencies
Note that, to construct ConfigLive
, we used the Config.of
constructor. However, this is merely a helper to ensure correct type inference
for the implementation. It’s possible to skip this helper and construct the
implementation directly as a simple object:
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3// Declaring a tag for the Config service9 collapsed lines
4class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<5 class Config
Config,6 {7 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{8 readonly (property) logLevel: string
logLevel: string9 readonly (property) connection: string
connection: string10 }>11 }12>() {}13
14// Layer<Config, never, never>15const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(class Config
Config, {16 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({17 (property) logLevel: string
logLevel: "INFO",18 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"19 })20})
Now we can move on to the implementation of the Logger
service, which depends on the Config
service to retrieve some configuration.
Just like we did in the Managing Services page, we can yield the Config
tag to “extract” the service from the context.
Given that using the Config
tag is an effectful operation, we use Layer.effect
to create a layer from the resulting effect.
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3// Declaring a tag for the Config service17 collapsed lines
4class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<5 class Config
Config,6 {7 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{8 readonly (property) logLevel: string
logLevel: string9 readonly (property) connection: string
connection: string10 }>11 }12>() {}13
14// Layer<Config, never, never>15const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(class Config
Config, {16 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({17 (property) logLevel: string
logLevel: "INFO",18 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"19 })20})21
22// Declaring a tag for the Logger service23class class Logger
Logger extends import Context
Context.const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>
namespace Tag
Tag("Logger")<24 class Logger
Logger,25 { readonly (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void> }26>() {}27
28// Layer<Logger, never, Config>29const const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive = import Layer
Layer.const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(30 class Logger
Logger,31 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {32 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config33 return {34 (property) log: (message: string) => Effect.Effect<void, never, never>
log: ((parameter) message: string
message) =>35 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {36 const { const logLevel: string
logLevel } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig37 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`[${const logLevel: string
logLevel}] ${(parameter) message: string
message}`)38 })39 }40 })41)
Looking at the type of LoggerLive
:
Layer<Logger, never, Config>
we can observe that:
RequirementsOut
isLogger
Error
isnever
, indicating that layer construction cannot failRequirementsIn
isConfig
, indicating that the layer has a requirement
Finally, we can use our Config
and Logger
services to implement the Database
service.
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3// Declaring a tag for the Config service17 collapsed lines
4class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<5 class Config
Config,6 {7 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{8 readonly (property) logLevel: string
logLevel: string9 readonly (property) connection: string
connection: string10 }>11 }12>() {}13
14// Layer<Config, never, never>15const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(class Config
Config, {16 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({17 (property) logLevel: string
logLevel: "INFO",18 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"19 })20})21
22// Declaring a tag for the Logger service19 collapsed lines
23class class Logger
Logger extends import Context
Context.const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>
namespace Tag
Tag("Logger")<24 class Logger
Logger,25 { readonly (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void> }26>() {}27
28// Layer<Logger, never, Config>29const const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive = import Layer
Layer.const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(30 class Logger
Logger,31 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {32 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config33 return {34 (property) log: (message: string) => Effect.Effect<void, never, never>
log: ((parameter) message: string
message) =>35 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {36 const { const logLevel: string
logLevel } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig37 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`[${const logLevel: string
logLevel}] ${(parameter) message: string
message}`)38 })39 }40 })41)42
43// Declaring a tag for the Database service44class class Database
Database extends import Context
Context.const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>
namespace Tag
Tag("Database")<45 class Database
Database,46 { readonly (property) query: (sql: string) => Effect.Effect<unknown>
query: ((parameter) sql: string
sql: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<unknown> }47>() {}48
49// Layer<Database, never, Config | Logger>50const const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive = import Layer
Layer.const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(51 class Database
Database,52 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {53 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config54 const const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger = yield* class Logger
Logger55 return {56 (property) query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query: ((parameter) sql: string
sql: string) =>57 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, {
result: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {58 yield* const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger.(property) log: (message: string) => Effect.Effect<void>
log(`Executing query: ${(parameter) sql: string
sql}`)59 const { const connection: string
connection } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig60 return { (property) result: string
result: `Results from ${const connection: string
connection}` }61 })62 }63 })64)
Looking at the type of DatabaseLive
:
Layer<Database, never, Config | Logger>
we can observe that the RequirementsIn
type is Config | Logger
, i.e., the Database
service requires both Config
and Logger
services.
Layers can be combined in two primary ways: merging and composing.
Layers can be combined through merging using the Layer.merge
function:
1import { import Layer
Layer } from "effect"2
3declare const const layer1: Layer.Layer<"Out1", never, "In1">
layer1: import Layer
Layer.interface Layer<in ROut, out E = never, out RIn = never>
namespace Layer
Layer<"Out1", never, "In1">4declare const const layer2: Layer.Layer<"Out2", never, "In2">
layer2: import Layer
Layer.interface Layer<in ROut, out E = never, out RIn = never>
namespace Layer
Layer<"Out2", never, "In2">5
6// Layer<"Out1" | "Out2", never, "In1" | "In2">7const const merging: Layer.Layer<"Out1" | "Out2", never, "In1" | "In2">
merging = import Layer
Layer.const merge: <"In1", never, "Out1", "In2", never, "Out2">(self: Layer.Layer<"Out1", never, "In1">, that: Layer.Layer<"Out2", never, "In2">) => Layer.Layer<"Out1" | "Out2", never, "In1" | "In2"> (+1 overload)
Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
merge(const layer1: Layer.Layer<"Out1", never, "In1">
layer1, const layer2: Layer.Layer<"Out2", never, "In2">
layer2)
When we merge two layers, the resulting layer:
- requires all the services that both of them require (
"In1" | "In2"
). - produces all services that both of them produce (
"Out1" | "Out2"
).
For example, in our web application above, we can merge our ConfigLive
and LoggerLive
layers into a single AppConfigLive
layer, which retains the requirements of both layers (never | Config = Config
) and the outputs of both layers (Config | Logger
):
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3// Declaring a tag for the Config service17 collapsed lines
4class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<5 class Config
Config,6 {7 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{8 readonly (property) logLevel: string
logLevel: string9 readonly (property) connection: string
connection: string10 }>11 }12>() {}13
14// Layer<Config, never, never>15const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(class Config
Config, {16 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({17 (property) logLevel: string
logLevel: "INFO",18 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"19 })20})21
22// Declaring a tag for the Logger service19 collapsed lines
23class class Logger
Logger extends import Context
Context.const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>
namespace Tag
Tag("Logger")<24 class Logger
Logger,25 { readonly (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void> }26>() {}27
28// Layer<Logger, never, Config>29const const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive = import Layer
Layer.const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(30 class Logger
Logger,31 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {32 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config33 return {34 (property) log: (message: string) => Effect.Effect<void, never, never>
log: ((parameter) message: string
message) =>35 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {36 const { const logLevel: string
logLevel } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig37 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`[${const logLevel: string
logLevel}] ${(parameter) message: string
message}`)38 })39 }40 })41)42
43// Layer<Config | Logger, never, Config>44const const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive = import Layer
Layer.const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)
Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
merge(const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive, const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive)
Layers can be composed using the Layer.provide
function:
1import { import Layer
Layer } from "effect"2
3declare const const inner: Layer.Layer<"OutInner", never, "InInner">
inner: import Layer
Layer.interface Layer<in ROut, out E = never, out RIn = never>
namespace Layer
Layer<"OutInner", never, "InInner">4declare const const outer: Layer.Layer<"InInner", never, "InOuter">
outer: import Layer
Layer.interface Layer<in ROut, out E = never, out RIn = never>
namespace Layer
Layer<"InInner", never, "InOuter">5
6// Layer<"OutInner", never, "InOuter">7const const composition: Layer.Layer<"OutInner", never, "InOuter">
composition = import Layer
Layer.const provide: <"InInner", never, "OutInner", "InOuter", never, "InInner">(self: Layer.Layer<"OutInner", never, "InInner">, that: Layer.Layer<"InInner", never, "InOuter">) => Layer.Layer<"OutInner", never, "InOuter"> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const inner: Layer.Layer<"OutInner", never, "InInner">
inner, const outer: Layer.Layer<"InInner", never, "InOuter">
outer)
Sequential composition of layers implies that the output of one layer is supplied as the input for the inner layer, resulting in a single layer with the requirements of the outer layer and the output of the inner.
Now we can compose the AppConfigLive
layer with the DatabaseLive
layer:
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3// Declaring a tag for the Config service17 collapsed lines
4class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<5 class Config
Config,6 {7 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{8 readonly (property) logLevel: string
logLevel: string9 readonly (property) connection: string
connection: string10 }>11 }12>() {}13
14// Layer<Config, never, never>15const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(class Config
Config, {16 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({17 (property) logLevel: string
logLevel: "INFO",18 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"19 })20})21
22// Declaring a tag for the Logger service19 collapsed lines
23class class Logger
Logger extends import Context
Context.const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>
namespace Tag
Tag("Logger")<24 class Logger
Logger,25 { readonly (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void> }26>() {}27
28// Layer<Logger, never, Config>29const const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive = import Layer
Layer.const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(30 class Logger
Logger,31 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {32 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config33 return {34 (property) log: (message: string) => Effect.Effect<void, never, never>
log: ((parameter) message: string
message) =>35 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {36 const { const logLevel: string
logLevel } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig37 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`[${const logLevel: string
logLevel}] ${(parameter) message: string
message}`)38 })39 }40 })41)42
43// Declaring a tag for the Database service21 collapsed lines
44class class Database
Database extends import Context
Context.const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>
namespace Tag
Tag("Database")<45 class Database
Database,46 { readonly (property) query: (sql: string) => Effect.Effect<unknown>
query: ((parameter) sql: string
sql: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<unknown> }47>() {}48
49// Layer<Database, never, Config | Logger>50const const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive = import Layer
Layer.const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(51 class Database
Database,52 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {53 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config54 const const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger = yield* class Logger
Logger55 return {56 (property) query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query: ((parameter) sql: string
sql: string) =>57 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, {
result: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {58 yield* const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger.(property) log: (message: string) => Effect.Effect<void>
log(`Executing query: ${(parameter) sql: string
sql}`)59 const { const connection: string
connection } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig60 return { (property) result: string
result: `Results from ${const connection: string
connection}` }61 })62 }63 })64)65
66// Layer<Config | Logger, never, Config>67const const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive = import Layer
Layer.const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)
Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
merge(const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive, const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive)68
69// Layer<Database, never, never>70const const MainLive: Layer.Layer<Database, never, never>
MainLive = const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive.(method) Pipeable.pipe<Layer.Layer<Database, never, Config | Logger>, Layer.Layer<Database, never, Config>, Layer.Layer<Database, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe(71 // provides the config and logger to the database72 import Layer
Layer.const provide: <Config, never, Config | Logger>(that: Layer.Layer<Config | Logger, never, Config>) => <RIn2, E2, ROut2>(self: Layer.Layer<...>) => Layer.Layer<...> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive),73 // provides the config to AppConfigLive74 import Layer
Layer.const provide: <never, never, Config>(that: Layer.Layer<Config, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<...> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive)75)
We obtained a MainLive
layer that produces the Database
service:
Layer<Database, never, never>
This layer is the fully resolved layer for our application.
Let’s say we want our MainLive
layer to return both the Config
and Database
services. We can achieve this with Layer.provideMerge
:
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3// Declaring a tag for the Config service16 collapsed lines
4class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<5 class Config
Config,6 {7 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{8 readonly (property) logLevel: string
logLevel: string9 readonly (property) connection: string
connection: string10 }>11 }12>() {}13
14const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(class Config
Config, {15 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({16 (property) logLevel: string
logLevel: "INFO",17 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"18 })19})20
21// Declaring a tag for the Logger service18 collapsed lines
22class class Logger
Logger extends import Context
Context.const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>
namespace Tag
Tag("Logger")<23 class Logger
Logger,24 { readonly (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void> }25>() {}26
27const const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive = import Layer
Layer.const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(28 class Logger
Logger,29 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {30 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config31 return {32 (property) log: (message: string) => Effect.Effect<void, never, never>
log: ((parameter) message: string
message) =>33 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {34 const { const logLevel: string
logLevel } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig35 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`[${const logLevel: string
logLevel}] ${(parameter) message: string
message}`)36 })37 }38 })39)40
41// Declaring a tag for the Database service20 collapsed lines
42class class Database
Database extends import Context
Context.const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>
namespace Tag
Tag("Database")<43 class Database
Database,44 { readonly (property) query: (sql: string) => Effect.Effect<unknown>
query: ((parameter) sql: string
sql: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<unknown> }45>() {}46
47const const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive = import Layer
Layer.const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(48 class Database
Database,49 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {50 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config51 const const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger = yield* class Logger
Logger52 return {53 (property) query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query: ((parameter) sql: string
sql: string) =>54 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, {
result: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {55 yield* const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger.(property) log: (message: string) => Effect.Effect<void>
log(`Executing query: ${(parameter) sql: string
sql}`)56 const { const connection: string
connection } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig57 return { (property) result: string
result: `Results from ${const connection: string
connection}` }58 })59 }60 })61)62
63// Layer<Config | Logger, never, Config>64const const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive = import Layer
Layer.const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)
Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
merge(const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive, const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive)65
66// Layer<Config | Database, never, never>67const const MainLive: Layer.Layer<Config | Database, never, never>
MainLive = const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive.(method) Pipeable.pipe<Layer.Layer<Database, never, Config | Logger>, Layer.Layer<Database, never, Config>, Layer.Layer<Config | Database, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe(68 import Layer
Layer.const provide: <Config, never, Config | Logger>(that: Layer.Layer<Config | Logger, never, Config>) => <RIn2, E2, ROut2>(self: Layer.Layer<...>) => Layer.Layer<...> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive),69 import Layer
Layer.const provideMerge: <never, never, Config>(self: Layer.Layer<Config, never, never>) => <RIn2, E2, ROut2>(that: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<...> (+1 overload)
Feeds the output services of this layer into the input of the specified
layer, resulting in a new layer with the inputs of this layer, and the
outputs of both layers.
provideMerge(const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive)70)
Now that we have assembled the fully resolved MainLive
for our application,
we can provide it to our program to satisfy the program’s requirements using Effect.provide
:
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
63 collapsed lines
3class class Config
Config extends import Context
Context.const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>
namespace Tag
Tag("Config")<4 class Config
Config,5 {6 readonly (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<{7 readonly (property) logLevel: string
logLevel: string8 readonly (property) connection: string
connection: string9 }>10 }11>() {}12
13const const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive = import Layer
Layer.const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)
Constructs a layer from the specified value.
succeed(class Config
Config, {14 (property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig: import Effect
Effect.const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({15 (property) logLevel: string
logLevel: "INFO",16 (property) connection: string
connection: "mysql://username:password@hostname:port/database_name"17 })18})19
20class class Logger
Logger extends import Context
Context.const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>
namespace Tag
Tag("Logger")<21 class Logger
Logger,22 { readonly (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void> }23>() {}24
25const const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive = import Layer
Layer.const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(26 class Logger
Logger,27 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {28 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config29 return {30 (property) log: (message: string) => Effect.Effect<void, never, never>
log: ((parameter) message: string
message) =>31 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {32 const { const logLevel: string
logLevel } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig33 namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`[${const logLevel: string
logLevel}] ${(parameter) message: string
message}`)34 })35 }36 })37)38
39class class Database
Database extends import Context
Context.const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>
namespace Tag
Tag("Database")<40 class Database
Database,41 { readonly (property) query: (sql: string) => Effect.Effect<unknown>
query: ((parameter) sql: string
sql: string) => import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<unknown> }42>() {}43
44const const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive = import Layer
Layer.const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)
Constructs a layer from the specified effect.
effect(45 class Database
Database,46 import Effect
Effect.const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {47 const const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config = yield* class Config
Config48 const const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger = yield* class Logger
Logger49 return {50 (property) query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query: ((parameter) sql: string
sql: string) =>51 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, {
result: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {52 yield* const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger.(property) log: (message: string) => Effect.Effect<void>
log(`Executing query: ${(parameter) sql: string
sql}`)53 const { const connection: string
connection } = yield* const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config.(property) getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig54 return { (property) result: string
result: `Results from ${const connection: string
connection}` }55 })56 }57 })58)59
60const const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive = import Layer
Layer.const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)
Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
merge(const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive, const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive)61
62const const MainLive: Layer.Layer<Database, never, never>
MainLive = const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive.(method) Pipeable.pipe<Layer.Layer<Database, never, Config | Logger>, Layer.Layer<Database, never, Config>, Layer.Layer<Database, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe(63 import Layer
Layer.const provide: <Config, never, Config | Logger>(that: Layer.Layer<Config | Logger, never, Config>) => <RIn2, E2, ROut2>(self: Layer.Layer<...>) => Layer.Layer<...> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive),64 import Layer
Layer.const provide: <never, never, Config>(that: Layer.Layer<Config, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<...> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive)65)66
67const const program: Effect.Effect<unknown, never, Database>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<Database, {
readonly query: (sql: string) => Effect.Effect<unknown>;
}>> | YieldWrap<Effect.Effect<unknown, never, never>>, unknown>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {68 const const database: {
readonly query: (sql: string) => Effect.Effect<unknown>;
}
database = yield* class Database
Database69 const const result: unknown
result = yield* const database: {
readonly query: (sql: string) => Effect.Effect<unknown>;
}
database.(property) query: (sql: string) => Effect.Effect<unknown>
query("SELECT * FROM users")70 return const result: unknown
result71})72
73const const runnable: Effect.Effect<unknown, never, never>
runnable = import Effect
Effect.const provide: <unknown, never, Database, Database, never, never>(self: Effect.Effect<unknown, never, Database>, layer: Layer.Layer<Database, never, never>) => Effect.Effect<...> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(const program: Effect.Effect<unknown, never, Database>
program, const MainLive: Layer.Layer<Database, never, never>
MainLive)74
75import Effect
Effect.const runPromise: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<unknown>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const runnable: Effect.Effect<unknown, never, never>
runnable).(method) Promise<unknown>.then<void, never>(onfulfilled?: ((value: unknown) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
Attaches callbacks for the resolution and/or rejection of the Promise.
then(namespace console
var console: Console
The `console` module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
* A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream.
* A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
_**Warning**_: The global console object's methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
```
Example using the `Console` class:
```js
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
```
console.(method) Console.log(message?: any, ...optionalParams: any[]): void
Prints to `stdout` with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
```
See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log)76/*77Output:78[INFO] Executing query: SELECT * FROM users79{80 result: 'Results from mysql://username:password@hostname:port/database_name'81}82*/