Managing Services
In the context of programming, a service refers to a reusable component or functionality that can be used by different parts of an application. Services are designed to provide specific capabilities and can be shared across multiple modules or components.
Services often encapsulate common tasks or operations that are needed by different parts of an application. They can handle complex operations, interact with external systems or APIs, manage data, or perform other specialized tasks.
Services are typically designed to be modular and decoupled from the rest of the application. This allows them to be easily maintained, tested, and replaced without affecting the overall functionality of the application.
When diving into services and their integration in application development, it helps to start from the basic principles of function management and dependency handling without relying on advanced constructs. Imagine having to manually pass a service around to every function that needs it:
const processData = (data: Data, databaseService: DatabaseService) => { // Operations using the database service}
This approach becomes cumbersome and unmanageable as your application grows, with services needing to be passed through multiple layers of functions.
To streamline this, you might consider using an environment object that bundles various services:
type Context = { databaseService: DatabaseService loggingService: LoggingService}
const processData = (data: Data, context: Context) => { // Using multiple services from the context}
However, this introduces a new complexity: you must ensure that the environment is correctly set up with all necessary services before it’s used, which can lead to tightly coupled code and makes functional composition and testing more difficult.
The Effect library simplifies managing these dependencies by leveraging the type system.
Instead of manually passing services or environment objects around, Effect allows you to declare service dependencies directly in the function’s type signature using the Requirements
parameter in the Effect
type:
Effect<Success, Error, Requirements>
This is how it works in practice when using Effect:
Dependency Declaration: You specify what services a function needs directly in its type, pushing the complexity of dependency management into the type system.
Service Provision: Effect.provideService
is used to make a service implementation available to the functions that need it. By providing services at the start, you ensure that all parts of your application have consistent access to the required services, thus maintaining a clean and decoupled architecture.
This approach abstracts away manual service handling, letting developers focus on business logic while the compiler ensures all dependencies are correctly managed. It also makes code more maintainable and scalable.
Let’s walk through managing services in Effect step by step:
- Creating a Service: Define a service with its unique functionality and interface.
- Using the Service: Access and utilize the service within your application’s functions.
- Providing a Service Implementation: Supply an actual implementation of the service to fulfill the declared requirements.
Up to this point, our examples with the Effect framework have dealt with effects that operate independently of external services.
This means the Requirements
parameter in our Effect
type signature has been set to never
, indicating no dependencies.
However, real-world applications often need effects that rely on specific services to function correctly. These services are managed and accessed through a construct known as Context
.
The Context
serves as a repository or container for all services an effect may require.
It acts like a store that maintains these services, allowing various parts of your application to access and use them as needed.
The services stored within the Context
are directly reflected in the Requirements
parameter of the Effect
type.
Each service within the Context
is identified by a unique “tag,” which is essentially a unique identifier for the service.
When an effect needs to use a specific service, the service’s tag is included in the Requirements
type parameter.
To create a new service, you need two things:
- A unique identifier.
- A type describing the possible operations of the service.
Example
Let’s create a service for generating random numbers.
- Identifier. We’ll use the string
"MyRandomService"
as the unique identifier. - Type. The service type will have a single operation called
next
that returns a random number.
1import { import Effect
Effect, import Context
Context } from "effect"2
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 { readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> }7>() {}
The exported Random
value is known as a tag in Effect. It acts as a representation of the service and allows Effect to locate and use this service at runtime.
The service will be stored in a collection called Context
, which can be thought of as a Map
where the keys are tags and the values are services:
type Context = Map<Tag, Service>
Let’s summarize the concepts we’ve covered so far:
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 service, functioning like a map with tags as keys and services as values. |
Now that we have our service tag defined, let’s see how we can use it by building a simple program.
1import { import Effect
Effect, import Context
Context } from "effect"2
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 { readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> }7>() {}8
9// Using the service10const const program: Effect.Effect<void, never, Random>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<Random, {
readonly next: Effect.Effect<number>;
}>> | YieldWrap<Effect.Effect<number, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {11 const const random: {
readonly next: Effect.Effect<number>;
}
random = yield* class Random
Random12 const const randomNumber: number
randomNumber = yield* const random: {
readonly next: Effect.Effect<number>;
}
random.(property) next: Effect.Effect<number, never, never>
next13 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(`random number: ${const randomNumber: number
randomNumber}`)14})
In the code above, we can observe that we are able to yield the Random
tag as if it were an effect itself.
This allows us to access the next
operation of the service.
1import { import Effect
Effect, import Context
Context, import Console
Console } from "effect"2
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 { readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> }7>() {}8
9// Using the service10const const program: Effect.Effect<void, never, Random>
program = class Random
Random.(method) Pipeable.pipe<typeof Random, Effect.Effect<number, never, Random>, Effect.Effect<void, never, Random>>(this: typeof Random, ab: (_: typeof Random) => Effect.Effect<number, never, Random>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(11 import Effect
Effect.const andThen: <{
readonly next: Effect.Effect<number>;
}, Effect.Effect<number, never, never>>(f: (a: {
readonly next: Effect.Effect<number>;
}) => Effect.Effect<number, never, never>) => <E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+3 overloads)
Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action.
The `that` action can take various forms:
- a value
- a function returning a value
- a promise
- a function returning a promise
- an effect
- a function returning an effect
andThen(((parameter) random: {
readonly next: Effect.Effect<number>;
}
random) => (parameter) random: {
readonly next: Effect.Effect<number>;
}
random.(property) next: Effect.Effect<number, never, never>
next),12 import Effect
Effect.const andThen: <number, Effect.Effect<void, never, never>>(f: (a: number) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<number, E, R>) => Effect.Effect<...> (+3 overloads)
Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action.
The `that` action can take various forms:
- a value
- a function returning a value
- a promise
- a function returning a promise
- an effect
- a function returning an effect
andThen(((parameter) randomNumber: number
randomNumber) =>13 import Console
Console.const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log(`random number: ${(parameter) randomNumber: number
randomNumber}`)14 )15)
In the code above, we can observe that we are able to flat-map over the Random
tag as if it were an effect itself.
This allows us to access the next
operation of the service within the Effect.andThen
callback.
It’s worth noting that the type of the program
variable includes Random
in the Requirements
type parameter:
const program: Effect<void, never, Random>
This indicates that our program requires the Random
service to be provided in order to execute successfully.
If we attempt to execute the effect without providing the necessary service we will encounter a type-checking error:
1import { import Effect
Effect, import Context
Context } from "effect"2
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 { readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> }7>() {}8
9// Using the service10const const program: Effect.Effect<void, never, Random>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<Random, {
readonly next: Effect.Effect<number>;
}>> | YieldWrap<Effect.Effect<number, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {11 const const random: {
readonly next: Effect.Effect<number>;
}
random = yield* class Random
Random12 const const randomNumber: number
randomNumber = yield* const random: {
readonly next: Effect.Effect<number>;
}
random.(property) next: Effect.Effect<number, never, never>
next13 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(`random number: ${const randomNumber: number
randomNumber}`)14})15
16// @ts-expect-error17import Effect
Effect.const runSync: <void, never>(effect: Effect.Effect<void, never, never>) => void
Executes an effect synchronously and returns its result.
Use `runSync` when you are certain that the effect is purely synchronous and will not perform any asynchronous operations.
If the effect fails or contains asynchronous tasks, it will throw an error.
runSync(const program: Effect.Effect<void, never, Random>
program)18/*19Argument of type 'Effect<void, never, Random>' is not assignable to parameter of type 'Effect<void, never, never>'.20 Type 'Random' is not assignable to type 'never'.ts(2345)21*/
To resolve this error and successfully execute the program, we need to provide an actual implementation of the Random
service.
In the next section, we will explore how to implement and provide the Random
service to our program, enabling us to run it successfully.
In order to provide an actual implementation of the Random
service, we can utilize the Effect.provideService
function.
1import { import Effect
Effect, import Context
Context } from "effect"2
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 { readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> }7>() {}8
9// Using the service10const const program: Effect.Effect<void, never, Random>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<Random, {
readonly next: Effect.Effect<number>;
}>> | YieldWrap<Effect.Effect<number, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {11 const const random: {
readonly next: Effect.Effect<number>;
}
random = yield* class Random
Random12 const const randomNumber: number
randomNumber = yield* const random: {
readonly next: Effect.Effect<number>;
}
random.(property) next: Effect.Effect<number, never, never>
next13 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(`random number: ${const randomNumber: number
randomNumber}`)14})15
16// Providing the implementation17const const runnable: Effect.Effect<void, never, never>
runnable = import Effect
Effect.const provideService: <void, never, Random, typeof Random>(self: Effect.Effect<void, never, Random>, tag: typeof Random, service: {
readonly next: Effect.Effect<number>;
}) => Effect.Effect<...> (+1 overload)
Provides the effect with the single service it requires. If the effect
requires more than one service use `provide` instead.
provideService(const program: Effect.Effect<void, never, Random>
program, class Random
Random, {18 (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.const sync: <number>(thunk: LazyArg<number>) => Effect.Effect<number, never, never>
Creates an `Effect` that represents a synchronous side-effectful computation.
The provided function (`thunk`) should not throw errors; if it does, the error is treated as a defect.
Use `Effect.sync` when you are certain the operation will not fail.
sync(() => var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math.(method) Math.random(): number
Returns a pseudorandom number between 0 and 1.
random())19})20
21// Run successfully22import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const runnable: Effect.Effect<void, never, never>
runnable)23/*24Example Output:25random number: 0.824187223313441726*/
In the code above, we provide the program
we defined earlier with an implementation of the Random
service.
We use the Effect.provideService
function to associate the Random
tag with its implementation, an object with a next
operation that generates a random number.
Notice that the Requirements
type parameter of the runnable
effect is now never
. This indicates that the effect no longer requires any service to be provided.
With the implementation of the Random
service in place, we are able to run the program without any further requirements.
To retrieve the service type from a tag, use the Context.Tag.Service
utility type.
Example
1import { import Effect
Effect, import Context
Context } from "effect"2
3// Declaring a tag4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 { readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> }7>() {}8
9// Extracting the type10type type RandomShape = {
readonly next: Effect.Effect<number>;
}
RandomShape = import Context
Context.namespace Tag
Tag.type Tag<in out Id, in out Value>.Service<T extends Context.Tag<any, any> | Context.TagClassShape<any, any>> = T extends Context.Tag<any, any> ? T["Service"] : T extends Context.TagClassShape<any, infer A> ? A : never
Service<class Random
Random>11/*12This is equivalent to:13type RandomShape = {14 readonly next: Effect.Effect<number>;15}16*/
When we require the usage of more than one service, the process remains similar to what we’ve learned in defining a service, repeated for each service needed.
Example
Let’s examine an example where we need two services, namely Random
and Logger
:
1import { import Effect
Effect, import Context
Context } from "effect"2
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 {7 readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number>8 }9>() {}10
11// Declaring a tag for the logging service12class class Logger
Logger extends import Context
Context.const Tag: <"MyLoggerService">(id: "MyLoggerService") => <Self, Shape>() => Context.TagClass<Self, "MyLoggerService", Shape>
namespace Tag
Tag("MyLoggerService")<13 class Logger
Logger,14 {15 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>16 }17>() {}18
19const const program: Effect.Effect<void, never, Random | Logger>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<Random, {
readonly next: Effect.Effect<number>;
}>> | YieldWrap<Context.Tag<Logger, {
readonly log: (message: string) => Effect.Effect<void>;
}>> | YieldWrap<...>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {20 // Acquire instances of the 'Random' and 'Logger' services21 const const random: {
readonly next: Effect.Effect<number>;
}
random = yield* class Random
Random22 const const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger = yield* class Logger
Logger23
24 const const randomNumber: number
randomNumber = yield* const random: {
readonly next: Effect.Effect<number>;
}
random.(property) next: Effect.Effect<number, never, never>
next25
26 yield* const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger.(property) log: (message: string) => Effect.Effect<void>
log(var String: StringConstructor
(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const randomNumber: number
randomNumber))27})
The program
effect now has a Requirements
type parameter of Random | Logger
:
const program: Effect<void, never, Random | Logger>
indicating that it requires both the Random
and Logger
services to be provided.
To execute the program
, we need to provide implementations for both services:
1import { import Effect
Effect, import Context
Context } from "effect"2
22 collapsed lines
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 {7 readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number>8 }9>() {}10
11// Declaring a tag for the logging service12class class Logger
Logger extends import Context
Context.const Tag: <"MyLoggerService">(id: "MyLoggerService") => <Self, Shape>() => Context.TagClass<Self, "MyLoggerService", Shape>
namespace Tag
Tag("MyLoggerService")<13 class Logger
Logger,14 {15 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>16 }17>() {}18
19const const program: Effect.Effect<void, never, Random | Logger>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<Logger, {
readonly log: (message: string) => Effect.Effect<void>;
}>> | YieldWrap<Context.Tag<Random, {
readonly next: Effect.Effect<number>;
}>> | YieldWrap<...>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {20 const const random: {
readonly next: Effect.Effect<number>;
}
random = yield* class Random
Random21 const const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger = yield* class Logger
Logger22 const const randomNumber: number
randomNumber = yield* const random: {
readonly next: Effect.Effect<number>;
}
random.(property) next: Effect.Effect<number, never, never>
next23 return yield* const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger.(property) log: (message: string) => Effect.Effect<void>
log(var String: StringConstructor
(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const randomNumber: number
randomNumber))24})25
26// Provide service implementations for 'Random' and 'Logger'27const const runnable: Effect.Effect<void, never, never>
runnable = const program: Effect.Effect<void, never, Random | Logger>
program.(method) Pipeable.pipe<Effect.Effect<void, never, Random | Logger>, Effect.Effect<void, never, Logger>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(28 import Effect
Effect.const provideService: <typeof Random>(tag: typeof Random, service: {
readonly next: Effect.Effect<number>;
}) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Random>> (+1 overload)
Provides the effect with the single service it requires. If the effect
requires more than one service use `provide` instead.
provideService(class Random
Random, {29 (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.const sync: <number>(thunk: LazyArg<number>) => Effect.Effect<number, never, never>
Creates an `Effect` that represents a synchronous side-effectful computation.
The provided function (`thunk`) should not throw errors; if it does, the error is treated as a defect.
Use `Effect.sync` when you are certain the operation will not fail.
sync(() => var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math.(method) Math.random(): number
Returns a pseudorandom number between 0 and 1.
random())30 }),31 import Effect
Effect.const provideService: <typeof Logger>(tag: typeof Logger, service: {
readonly log: (message: string) => Effect.Effect<void>;
}) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+1 overload)
Provides the effect with the single service it requires. If the effect
requires more than one service use `provide` instead.
provideService(class Logger
Logger, {32 (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message) => import Effect
Effect.const sync: <void>(thunk: LazyArg<void>) => Effect.Effect<void, never, never>
Creates an `Effect` that represents a synchronous side-effectful computation.
The provided function (`thunk`) should not throw errors; if it does, the error is treated as a defect.
Use `Effect.sync` when you are certain the operation will not fail.
sync(() => 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((parameter) message: string
message))33 })34)
Alternatively, instead of calling provideService
multiple times, we can combine the service implementations into a single Context
and then provide the entire context using the Effect.provide
function:
1import { import Effect
Effect, import Context
Context } from "effect"2
22 collapsed lines
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 {7 readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number>8 }9>() {}10
11// Declaring a tag for the logging service12class class Logger
Logger extends import Context
Context.const Tag: <"MyLoggerService">(id: "MyLoggerService") => <Self, Shape>() => Context.TagClass<Self, "MyLoggerService", Shape>
namespace Tag
Tag("MyLoggerService")<13 class Logger
Logger,14 {15 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>16 }17>() {}18
19const const program: Effect.Effect<void, never, Random | Logger>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<Logger, {
readonly log: (message: string) => Effect.Effect<void>;
}>> | YieldWrap<Context.Tag<Random, {
readonly next: Effect.Effect<number>;
}>> | YieldWrap<...>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {20 const const random: {
readonly next: Effect.Effect<number>;
}
random = yield* class Random
Random21 const const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger = yield* class Logger
Logger22 const const randomNumber: number
randomNumber = yield* const random: {
readonly next: Effect.Effect<number>;
}
random.(property) next: Effect.Effect<number, never, never>
next23 return yield* const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger.(property) log: (message: string) => Effect.Effect<void>
log(var String: StringConstructor
(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const randomNumber: number
randomNumber))24})25
26// Combine service implementations into a single 'Context'27const const context: Context.Context<Random | Logger>
context = import Context
Context.const empty: () => Context.Context<never>
Returns an empty `Context`.
empty().(method) Pipeable.pipe<Context.Context<never>, Context.Context<Random>, Context.Context<Random | Logger>>(this: Context.Context<...>, ab: (_: Context.Context<never>) => Context.Context<...>, bc: (_: Context.Context<...>) => Context.Context<...>): Context.Context<...> (+21 overloads)
pipe(28 import Context
Context.const add: <typeof Random>(tag: typeof Random, service: {
readonly next: Effect.Effect<number>;
}) => <Services>(self: Context.Context<Services>) => Context.Context<Random | Services> (+1 overload)
Adds a service to a given `Context`.
add(class Random
Random, { (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.const sync: <number>(thunk: LazyArg<number>) => Effect.Effect<number, never, never>
Creates an `Effect` that represents a synchronous side-effectful computation.
The provided function (`thunk`) should not throw errors; if it does, the error is treated as a defect.
Use `Effect.sync` when you are certain the operation will not fail.
sync(() => var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math.(method) Math.random(): number
Returns a pseudorandom number between 0 and 1.
random()) }),29 import Context
Context.const add: <typeof Logger>(tag: typeof Logger, service: {
readonly log: (message: string) => Effect.Effect<void>;
}) => <Services>(self: Context.Context<Services>) => Context.Context<...> (+1 overload)
Adds a service to a given `Context`.
add(class Logger
Logger, {30 (property) log: (message: string) => Effect.Effect<void>
log: ((parameter) message: string
message) => import Effect
Effect.const sync: <void>(thunk: LazyArg<void>) => Effect.Effect<void, never, never>
Creates an `Effect` that represents a synchronous side-effectful computation.
The provided function (`thunk`) should not throw errors; if it does, the error is treated as a defect.
Use `Effect.sync` when you are certain the operation will not fail.
sync(() => 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((parameter) message: string
message))31 })32)33
34// Provide the entire context35const const runnable: Effect.Effect<void, never, never>
runnable = import Effect
Effect.const provide: <void, never, Random | Logger, Random | Logger>(self: Effect.Effect<void, never, Random | Logger>, context: Context.Context<Random | Logger>) => 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<void, never, Random | Logger>
program, const context: Context.Context<Random | Logger>
context)
There are situations where we may want to access a service implementation only if it is available.
In such cases, we can use the Effect.serviceOption
function to handle this scenario.
The Effect.serviceOption
function returns an implementation that is available only if it is actually provided before executing this effect.
To represent this optionality it returns an Option of the implementation.
Example
To determine what action to take, we can use the Option.isNone
function provided by the Option module. This function allows us to check if the service is available or not by returning true
when the service is not available.
1import { import Effect
Effect, import Context
Context, import Option
Option } from "effect"2
3// Declaring a tag for a service that generates random numbers4class class Random
Random extends import Context
Context.const Tag: <"MyRandomService">(id: "MyRandomService") => <Self, Shape>() => Context.TagClass<Self, "MyRandomService", Shape>
namespace Tag
Tag("MyRandomService")<5 class Random
Random,6 { readonly (property) next: Effect.Effect<number, never, never>
next: import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> }7>() {}8
9const const program: Effect.Effect<void, never, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<Option.Option<{
readonly next: Effect.Effect<number>;
}>, never, never>> | YieldWrap<Effect.Effect<number, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {10 const const maybeRandom: Option.Option<{
readonly next: Effect.Effect<number>;
}>
maybeRandom = yield* import Effect
Effect.const serviceOption: <Random, {
readonly next: Effect.Effect<number>;
}>(tag: Context.Tag<Random, {
readonly next: Effect.Effect<number>;
}>) => Effect.Effect<Option.Option<{
readonly next: Effect.Effect<number>;
}>, never, never>
serviceOption(class Random
Random)11 const const randomNumber: number
randomNumber = import Option
Option.const isNone: <{
readonly next: Effect.Effect<number>;
}>(self: Option.Option<{
readonly next: Effect.Effect<number>;
}>) => self is Option.None<{
readonly next: Effect.Effect<number>;
}>
Determine if a `Option` is a `None`.
isNone(const maybeRandom: Option.Option<{
readonly next: Effect.Effect<number>;
}>
maybeRandom)12 ? // the service is not available, return a default value13 -114 : // the service is available15 yield* const maybeRandom: Option.Some<{
readonly next: Effect.Effect<number>;
}>
maybeRandom.(property) Some<{ readonly next: Effect.Effect<number>; }>.value: {
readonly next: Effect.Effect<number>;
}
value.(property) next: Effect.Effect<number, never, never>
next16 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 randomNumber: number
randomNumber)17})
In the code above, we can observe that the Requirements
type parameter of the program
effect is never
, even though we are working with a service. This allows us to access something from the context only if it is actually provided before executing this effect.
When we run the program
effect without providing the Random
service:
Effect.runPromise(program).then(console.log)// Output: -1
We see that the log message contains -1
, which is the default value we provided when the service was not available.
However, if we provide the Random
service implementation:
Effect.runPromise( Effect.provideService(program, Random, { next: Effect.sync(() => Math.random()) })).then(console.log)// Example Output: 0.9957979486841035
We can observe that the log message now contains a random number generated by the next
operation of the Random
service.