Skip to content

Resourceful Streams

In the Stream module, you’ll find that most of the constructors offer a special variant designed for lifting a scoped resource into a Stream. When you use these specific constructors, you’re essentially creating streams that are inherently safe with regards to resource management. These constructors, before creating the stream, handle the resource acquisition, and after the stream’s usage, they ensure its proper closure.

Stream also provides us with Stream.acquireRelease and Stream.finalizer constructors that share similarities with Effect.acquireRelease and Effect.addFinalizer. These tools empower us to perform cleanup or finalization tasks before the stream concludes its operation.

In this section, we’ll explore an example that demonstrates the use of Stream.acquireRelease when working with file operations.

import {
import Stream
Stream
,
import Console
Console
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// Simulating File operations
const
const open: (filename: string) => Effect.Effect<{
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}, never, never>
open
= (
filename: string
filename
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, {
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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

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

@example

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

@since2.0.0

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

@since2.0.0

log
(`Opening ${
filename: string
filename
}`)
return {
getLines: Effect.Effect<string[], never, never>
getLines
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <string[]>(value: string[]) => Effect.Effect<string[], never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
(["Line 1", "Line 2", "Line 3"]),
close: Effect.Effect<void, never, never>
close
:
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`Closing ${
filename: string
filename
}`)
}
})
const
const stream: Stream.Stream<string[], never, never>
stream
=
import Stream
Stream
.
const acquireRelease: <{
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}, never, never, never, void>(acquire: Effect.Effect<{
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}, never, never>, release: (resource: {
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}, exit: Exit<unknown, unknown>) => Effect.Effect<...>) => Stream.Stream<...>

Creates a stream from a single value that will get cleaned up after the stream is consumed.

@example

import { Console, Effect, Stream } from "effect"
// Simulating File operations
const open = (filename: string) =>
Effect.gen(function*() {
yield* Console.log(`Opening ${filename}`)
return {
getLines: Effect.succeed(["Line 1", "Line 2", "Line 3"]),
close: Console.log(`Closing ${filename}`)
}
})
const stream = Stream.acquireRelease(
open("file.txt"),
(file) => file.close
).pipe(Stream.flatMap((file) => file.getLines))
// Effect.runPromise(Stream.runCollect(stream)).then(console.log)
// Opening file.txt
// Closing file.txt
// { _id: 'Chunk', values: [ [ 'Line 1', 'Line 2', 'Line 3' ] ] }

@since2.0.0

acquireRelease
(
const open: (filename: string) => Effect.Effect<{
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}, never, never>
open
("file.txt"),
(
file: {
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}
file
) =>
file: {
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}
file
.
close: Effect.Effect<void, never, never>
close
).
Pipeable.pipe<Stream.Stream<{
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}, never, never>, Stream.Stream<string[], never, never>>(this: Stream.Stream<...>, ab: (_: Stream.Stream<...>) => Stream.Stream<...>): Stream.Stream<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const flatMap: <{
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}, string[], never, never>(f: (a: {
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}) => Stream.Stream<...>, options?: {
readonly concurrency?: number | "unbounded" | undefined;
readonly bufferSize?: number | undefined;
readonly switch?: boolean | undefined;
} | undefined) => <E, R>(self: Stream.Stream<...>) => Stream.Stream<...> (+1 overload)

Returns a stream made of the concatenation in strict order of all the streams produced by passing each element of this stream to f0

@since2.0.0

flatMap
((
file: {
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}
file
) =>
file: {
getLines: Effect.Effect<string[], never, never>;
close: Effect.Effect<void, never, never>;
}
file
.
getLines: Effect.Effect<string[], never, never>
getLines
))
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

When to Use

Use runPromise when you need to execute an effect and work with the result using Promise syntax, typically for compatibility with other promise-based code.

If the effect succeeds, the promise will resolve with the result. If the effect fails, the promise will reject with an error.

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

@example

// Title: Running a Successful Effect as a Promise
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

@example

//Example: Handling a Failing Effect as a Rejected Promise import { Effect } from "effect"

Effect.runPromise(Effect.fail("my error")).catch(console.error) // Output: // (FiberFailure) Error: my error

@since2.0.0

runPromise
(
import Stream
Stream
.
const runCollect: <string[], never, never>(self: Stream.Stream<string[], never, never>) => Effect.Effect<Chunk<string[]>, never, never>

Runs the stream and collects all of its elements to a chunk.

@since2.0.0

runCollect
(
const stream: Stream.Stream<string[], never, never>
stream
)).
Promise<Chunk<string[]>>.then<void, never>(onfulfilled?: ((value: Chunk<string[]>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

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

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

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

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

then
(
var console: Console

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

The module exports two specific components:

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

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

Example using the global console:

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

Example using the Console class:

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

@seesource

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

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

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

See util.format() for more information.

@sincev0.1.100

log
)
/*
Output:
Opening file.txt
Closing file.txt
{
_id: "Chunk",
values: [
[ "Line 1", "Line 2", "Line 3" ]
]
}
*/

In this code snippet, we’re simulating file operations using the open function. The Stream.acquireRelease function is employed to ensure that the file is correctly opened and closed, and we then process the lines of the file using the acquired resource.

In this section, we’ll explore the concept of finalization in streams. Finalization allows us to execute a specific action before a stream ends. This can be particularly useful when we want to perform cleanup tasks or add final touches to a stream.

Imagine a scenario where our streaming application needs to clean up a temporary directory when it completes its execution. We can achieve this using the Stream.finalizer function:

import {
import Stream
Stream
,
import Console
Console
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const application: Stream.Stream<void, never, never>
application
=
import Stream
Stream
.
const fromEffect: <void, never, never>(effect: Effect.Effect<void, never, never>) => Stream.Stream<void, never, never>

Either emits the success value of this effect or terminates the stream with the failure value of this effect.

@example

import { Effect, Random, Stream } from "effect"
const stream = Stream.fromEffect(Random.nextInt)
// Effect.runPromise(Stream.runCollect(stream)).then(console.log)
// Example Output: { _id: 'Chunk', values: [ 922694024 ] }

@since2.0.0

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

@since2.0.0

log
("Application Logic."))
const
const deleteDir: (dir: string) => Effect.Effect<void, never, never>
deleteDir
= (
dir: string
dir
: string) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(`Deleting dir: ${
dir: string
dir
}`)
const
const program: Stream.Stream<void, never, never>
program
=
const application: Stream.Stream<void, never, never>
application
.
Pipeable.pipe<Stream.Stream<void, never, never>, Stream.Stream<void, never, never>>(this: Stream.Stream<...>, ab: (_: Stream.Stream<void, never, never>) => Stream.Stream<void, never, never>): Stream.Stream<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const concat: <void, never, never>(that: Stream.Stream<void, never, never>) => <A, E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<void | A, E, R> (+1 overload)

Concatenates the specified stream with this stream, resulting in a stream that emits the elements from this stream and then the elements from the specified stream.

@example

import { Effect, Stream } from "effect"
const s1 = Stream.make(1, 2, 3)
const s2 = Stream.make(4, 5)
const stream = Stream.concat(s1, s2)
// Effect.runPromise(Stream.runCollect(stream)).then(console.log)
// { _id: 'Chunk', values: [ 1, 2, 3, 4, 5 ] }

@since2.0.0

concat
(
import Stream
Stream
.
const finalizer: <never, void>(finalizer: Effect.Effect<void, never, never>) => Stream.Stream<void, never, never>

Creates a one-element stream that never fails and executes the finalizer when it ends.

@example

import { Console, Effect, Stream } from "effect"
const application = Stream.fromEffect(Console.log("Application Logic."))
const deleteDir = (dir: string) => Console.log(`Deleting dir: ${dir}`)
const program = application.pipe(
Stream.concat(
Stream.finalizer(
deleteDir("tmp").pipe(
Effect.andThen(Console.log("Temporary directory was deleted."))
)
)
)
)
// Effect.runPromise(Stream.runCollect(program)).then(console.log)
// Application Logic.
// Deleting dir: tmp
// Temporary directory was deleted.
// { _id: 'Chunk', values: [ undefined, undefined ] }

@since2.0.0

finalizer
(
const deleteDir: (dir: string) => Effect.Effect<void, never, never>
deleteDir
("tmp").
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

Syntax

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

When to Use

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

Details

The second action can be:

  • A constant value (similar to

as

)

  • A function returning a value (similar to

map

)

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

flatMap

)

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

@example

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

@since2.0.0

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

@since2.0.0

log
("Temporary directory was deleted."))
)
)
)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

When to Use

Use runPromise when you need to execute an effect and work with the result using Promise syntax, typically for compatibility with other promise-based code.

If the effect succeeds, the promise will resolve with the result. If the effect fails, the promise will reject with an error.

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

@example

// Title: Running a Successful Effect as a Promise
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

@example

//Example: Handling a Failing Effect as a Rejected Promise import { Effect } from "effect"

Effect.runPromise(Effect.fail("my error")).catch(console.error) // Output: // (FiberFailure) Error: my error

@since2.0.0

runPromise
(
import Stream
Stream
.
const runCollect: <void, never, never>(self: Stream.Stream<void, never, never>) => Effect.Effect<Chunk<void>, never, never>

Runs the stream and collects all of its elements to a chunk.

@since2.0.0

runCollect
(
const program: Stream.Stream<void, never, never>
program
)).
Promise<Chunk<void>>.then<void, never>(onfulfilled?: ((value: Chunk<void>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

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

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

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

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

then
(
var console: Console

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

The module exports two specific components:

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

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

Example using the global console:

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

Example using the Console class:

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

@seesource

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

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

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

See util.format() for more information.

@sincev0.1.100

log
)
/*
Output:
Application Logic.
Deleting dir: tmp
Temporary directory was deleted.
{
_id: "Chunk",
values: [ undefined, undefined ]
}
*/

In this code example, we start with our application logic represented by the application stream. We then use Stream.finalizer to define a finalization step, which deletes a temporary directory and logs a message. This ensures that the temporary directory is cleaned up properly when the application completes its execution.

In this section, we’ll explore a scenario where we need to perform actions after the finalization of a stream. To achieve this, we can utilize the Stream.ensuring operator.

Consider a situation where our application has completed its primary logic and finalized some resources, but we also need to perform additional actions afterward. We can use Stream.ensuring for this purpose:

import {
import Stream
Stream
,
import Console
Console
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Stream.Stream<void, never, never>
program
=
import Stream
Stream
.
const fromEffect: <void, never, never>(effect: Effect.Effect<void, never, never>) => Stream.Stream<void, never, never>

Either emits the success value of this effect or terminates the stream with the failure value of this effect.

@example

import { Effect, Random, Stream } from "effect"
const stream = Stream.fromEffect(Random.nextInt)
// Effect.runPromise(Stream.runCollect(stream)).then(console.log)
// Example Output: { _id: 'Chunk', values: [ 922694024 ] }

@since2.0.0

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

@since2.0.0

log
("Application Logic.")).
Pipeable.pipe<Stream.Stream<void, never, never>, Stream.Stream<void, never, never>, Stream.Stream<void, never, never>>(this: Stream.Stream<...>, ab: (_: Stream.Stream<void, never, never>) => Stream.Stream<...>, bc: (_: Stream.Stream<...>) => Stream.Stream<...>): Stream.Stream<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const concat: <void, never, never>(that: Stream.Stream<void, never, never>) => <A, E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<void | A, E, R> (+1 overload)

Concatenates the specified stream with this stream, resulting in a stream that emits the elements from this stream and then the elements from the specified stream.

@example

import { Effect, Stream } from "effect"
const s1 = Stream.make(1, 2, 3)
const s2 = Stream.make(4, 5)
const stream = Stream.concat(s1, s2)
// Effect.runPromise(Stream.runCollect(stream)).then(console.log)
// { _id: 'Chunk', values: [ 1, 2, 3, 4, 5 ] }

@since2.0.0

concat
(
import Stream
Stream
.
const finalizer: <never, void>(finalizer: Effect.Effect<void, never, never>) => Stream.Stream<void, never, never>

Creates a one-element stream that never fails and executes the finalizer when it ends.

@example

import { Console, Effect, Stream } from "effect"
const application = Stream.fromEffect(Console.log("Application Logic."))
const deleteDir = (dir: string) => Console.log(`Deleting dir: ${dir}`)
const program = application.pipe(
Stream.concat(
Stream.finalizer(
deleteDir("tmp").pipe(
Effect.andThen(Console.log("Temporary directory was deleted."))
)
)
)
)
// Effect.runPromise(Stream.runCollect(program)).then(console.log)
// Application Logic.
// Deleting dir: tmp
// Temporary directory was deleted.
// { _id: 'Chunk', values: [ undefined, undefined ] }

@since2.0.0

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

@since2.0.0

log
("Finalizing the stream"))),
import Stream
Stream
.
const ensuring: <void, never>(finalizer: Effect.Effect<void, never, never>) => <A, E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<A, E, R> (+1 overload)

Executes the provided finalizer after this stream's finalizers run.

@example

import { Console, Effect, Stream } from "effect"
const program = Stream.fromEffect(Console.log("Application Logic.")).pipe(
Stream.concat(Stream.finalizer(Console.log("Finalizing the stream"))),
Stream.ensuring(
Console.log("Doing some other works after stream's finalization")
)
)
// Effect.runPromise(Stream.runCollect(program)).then(console.log)
// Application Logic.
// Finalizing the stream
// Doing some other works after stream's finalization
// { _id: 'Chunk', values: [ undefined, undefined ] }

@since2.0.0

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

@since2.0.0

log
("Doing some other works after stream's finalization")
)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Executes an effect and returns the result as a Promise.

When to Use

Use runPromise when you need to execute an effect and work with the result using Promise syntax, typically for compatibility with other promise-based code.

If the effect succeeds, the promise will resolve with the result. If the effect fails, the promise will reject with an error.

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

@example

// Title: Running a Successful Effect as a Promise
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

@example

//Example: Handling a Failing Effect as a Rejected Promise import { Effect } from "effect"

Effect.runPromise(Effect.fail("my error")).catch(console.error) // Output: // (FiberFailure) Error: my error

@since2.0.0

runPromise
(
import Stream
Stream
.
const runCollect: <void, never, never>(self: Stream.Stream<void, never, never>) => Effect.Effect<Chunk<void>, never, never>

Runs the stream and collects all of its elements to a chunk.

@since2.0.0

runCollect
(
const program: Stream.Stream<void, never, never>
program
)).
Promise<Chunk<void>>.then<void, never>(onfulfilled?: ((value: Chunk<void>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

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

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

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

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

then
(
var console: Console

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

The module exports two specific components:

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

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

Example using the global console:

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

Example using the Console class:

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

@seesource

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

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

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

See util.format() for more information.

@sincev0.1.100

log
)
/*
Output:
Application Logic.
Finalizing the stream
Doing some other works after stream's finalization
{
_id: "Chunk",
values: [ undefined, undefined ]
}
*/

In this code example, we start with our application logic represented by the Application Logic. message. We then use Stream.finalizer to specify the finalization step, which logs Finalizing the stream. After that, we use Stream.ensuring to indicate that we want to perform additional tasks after the stream’s finalization, resulting in the message Performing additional tasks after stream's finalization. This ensures that our post-finalization actions are executed as expected.