Skip to content

Terminal

The @effect/platform/Terminal module provides an abstraction for interacting with standard input and output, including reading user input and displaying messages on the terminal.

The module provides a single Terminal tag, which serves as the entry point to reading from and writing to standard input and standard output.

Example (Using the Terminal Service)

import {
import Terminal
Terminal
} from "@effect/platform"
import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, Terminal.Terminal>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

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

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

@example

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

@since2.0.0

gen
(function* () {
const
const terminal: Terminal.Terminal
terminal
= yield*
import Terminal
Terminal
.
const Terminal: Tag<Terminal.Terminal, Terminal.Terminal>

A Terminal represents a command-line interface which can read input from a user and display messages to a user.

@since1.0.0

@since1.0.0

Terminal
// Use `terminal` to interact with standard input and output
})

Example (Displaying a Message on the Terminal)

import {
import Terminal
Terminal
} from "@effect/platform"
import {
import NodeRuntime
NodeRuntime
,
import NodeTerminal
NodeTerminal
} from "@effect/platform-node"
import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, PlatformError, Terminal.Terminal>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Tag<Terminal.Terminal, Terminal.Terminal>> | YieldWrap<Effect.Effect<void, PlatformError, never>>, void>(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* () {
const
const terminal: Terminal.Terminal
terminal
= yield*
import Terminal
Terminal
.
const Terminal: Tag<Terminal.Terminal, Terminal.Terminal>

A Terminal represents a command-line interface which can read input from a user and display messages to a user.

@since1.0.0

@since1.0.0

Terminal
yield*
const terminal: Terminal.Terminal
terminal
.
Terminal.display: (text: string) => Effect.Effect<void, PlatformError>

Displays text to the the default standard output.

display
("a message\n")
})
import NodeRuntime
NodeRuntime
.
const runMain: RunMain
<PlatformError, void>(effect: Effect.Effect<void, PlatformError, never>, options?: {
readonly disableErrorReporting?: boolean | undefined;
readonly disablePrettyLogger?: boolean | undefined;
readonly teardown?: Teardown | undefined;
}) => void (+1 overload)
runMain
(
const program: Effect.Effect<void, PlatformError, Terminal.Terminal>
program
.
Pipeable.pipe<Effect.Effect<void, PlatformError, Terminal.Terminal>, Effect.Effect<void, PlatformError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, PlatformError, Terminal.Terminal>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Terminal.Terminal, never, never>(layer: Layer<Terminal.Terminal, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+9 overloads)

Provides the necessary Layers to an effect, removing its dependency on the environment.

You can pass multiple layers, a Context, Runtime, or ManagedRuntime to the effect.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import NodeTerminal
NodeTerminal
.
const layer: Layer<Terminal.Terminal, never, never>

@since1.0.0

layer
)))
// Output: "a message"

Example (Reading a Line from Standard Input)

import {
import Terminal
Terminal
} from "@effect/platform"
import {
import NodeRuntime
NodeRuntime
,
import NodeTerminal
NodeTerminal
} from "@effect/platform-node"
import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, Terminal.QuitException, Terminal.Terminal>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Tag<Terminal.Terminal, Terminal.Terminal>> | YieldWrap<Effect.Effect<string, Terminal.QuitException, never>>, void>(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* () {
const
const terminal: Terminal.Terminal
terminal
= yield*
import Terminal
Terminal
.
const Terminal: Tag<Terminal.Terminal, Terminal.Terminal>

A Terminal represents a command-line interface which can read input from a user and display messages to a user.

@since1.0.0

@since1.0.0

Terminal
const
const input: string
input
= yield*
const terminal: Terminal.Terminal
terminal
.
Terminal.readLine: Effect.Effect<string, Terminal.QuitException, never>

Reads a single line from the default standard input.

readLine
var console: Console

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

The module exports two specific components:

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

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

Example using the global console:

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

Example using the Console class:

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

@seesource

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

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

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

See util.format() for more information.

@sincev0.1.100

log
(`input: ${
const input: string
input
}`)
})
import NodeRuntime
NodeRuntime
.
const runMain: RunMain
<Terminal.QuitException, void>(effect: Effect.Effect<void, Terminal.QuitException, never>, options?: {
readonly disableErrorReporting?: boolean | undefined;
readonly disablePrettyLogger?: boolean | undefined;
readonly teardown?: Teardown | undefined;
}) => void (+1 overload)
runMain
(
const program: Effect.Effect<void, Terminal.QuitException, Terminal.Terminal>
program
.
Pipeable.pipe<Effect.Effect<void, Terminal.QuitException, Terminal.Terminal>, Effect.Effect<void, Terminal.QuitException, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Terminal.Terminal, never, never>(layer: Layer<Terminal.Terminal, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+9 overloads)

Provides the necessary Layers to an effect, removing its dependency on the environment.

You can pass multiple layers, a Context, Runtime, or ManagedRuntime to the effect.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import NodeTerminal
NodeTerminal
.
const layer: Layer<Terminal.Terminal, never, never>

@since1.0.0

layer
)))
// Input: "hello"
// Output: "input: hello"

This example demonstrates how to create a complete number-guessing game by reading input from the terminal and providing feedback to the user. The game continues until the user guesses the correct number.

Example (Interactive Number Guessing Game)

import {
import Terminal
Terminal
} from "@effect/platform"
import type {
type PlatformError = BadArgument | SystemError

@since1.0.0

@since1.0.0

PlatformError
} from "@effect/platform/Error"
import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Option

@since2.0.0

@since2.0.0

Option
,
import Random
Random
} from "effect"
import {
import NodeRuntime
NodeRuntime
,
import NodeTerminal
NodeTerminal
} from "@effect/platform-node"
// Generate a secret random number between 1 and 100
const
const secret: Effect.Effect<number, never, never>
secret
=
import Random
Random
.
const nextIntBetween: (min: number, max: number) => Effect.Effect<number>

Returns the next integer value in the specified range from the pseudo-random number generator.

@since2.0.0

nextIntBetween
(1, 100)
// Parse the user's input into a valid number
const
const parseGuess: (input: string) => Option.None<number> | Option.Some<number>
parseGuess
= (
input: string
input
: string) => {
const
const n: number
n
=
function parseInt(string: string, radix?: number): number

Converts a string to an integer.

@paramstring A string to convert into a number.

@paramradix A value between 2 and 36 that specifies the base of the number in string. If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal. All other strings are considered decimal.

parseInt
(
input: string
input
, 10)
return
function isNaN(number: number): boolean

Returns a Boolean value that indicates whether a value is the reserved value NaN (not a number).

@paramnumber A numeric value.

isNaN
(
const n: number
n
) ||
const n: number
n
< 1 ||
const n: number
n
> 100 ?
import Option

@since2.0.0

@since2.0.0

Option
.
const none: <never>() => Option.Option<never>

Creates a new Option that represents the absence of a value.

@since2.0.0

none
() :
import Option

@since2.0.0

@since2.0.0

Option
.
const some: <number>(value: number) => Option.Option<number>

Creates a new Option that wraps the given value.

@paramvalue - The value to wrap.

@since2.0.0

some
(
const n: number
n
)
}
// Display a message on the terminal
const
const display: (message: string) => Effect.Effect<void, PlatformError, Terminal.Terminal>
display
= (
message: string
message
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Tag<Terminal.Terminal, Terminal.Terminal>> | YieldWrap<Effect.Effect<void, PlatformError, never>>, void>(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* () {
const
const terminal: Terminal.Terminal
terminal
= yield*
import Terminal
Terminal
.
const Terminal: Tag<Terminal.Terminal, Terminal.Terminal>

A Terminal represents a command-line interface which can read input from a user and display messages to a user.

@since1.0.0

@since1.0.0

Terminal
yield*
const terminal: Terminal.Terminal
terminal
.
Terminal.display: (text: string) => Effect.Effect<void, PlatformError>

Displays text to the the default standard output.

display
(`${
message: string
message
}\n`)
})
// Prompt the user for a guess
const
const prompt: Effect.Effect<string, PlatformError | Terminal.QuitException, Terminal.Terminal>
prompt
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Tag<Terminal.Terminal, Terminal.Terminal>> | YieldWrap<Effect.Effect<void, PlatformError, never>> | YieldWrap<...>, string>(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* () {
const
const terminal: Terminal.Terminal
terminal
= yield*
import Terminal
Terminal
.
const Terminal: Tag<Terminal.Terminal, Terminal.Terminal>

A Terminal represents a command-line interface which can read input from a user and display messages to a user.

@since1.0.0

@since1.0.0

Terminal
yield*
const terminal: Terminal.Terminal
terminal
.
Terminal.display: (text: string) => Effect.Effect<void, PlatformError>

Displays text to the the default standard output.

display
("Enter a guess: ")
return yield*
const terminal: Terminal.Terminal
terminal
.
Terminal.readLine: Effect.Effect<string, Terminal.QuitException, never>

Reads a single line from the default standard input.

readLine
})
// Get the user's guess, validating it as an integer between 1 and 100
const
const answer: Effect.Effect<number, PlatformError | Terminal.QuitException, Terminal.Terminal>
answer
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

The Effect interface defines a value that 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.

@since2.0.0

@since2.0.0

Effect
<
number,
import Terminal
Terminal
.
class QuitException

A QuitException represents an exception that occurs when a user attempts to quit out of a Terminal prompt for input (usually by entering ctrl+c).

@since1.0.0

QuitException
|
type PlatformError = BadArgument | SystemError

@since1.0.0

@since1.0.0

PlatformError
,
import Terminal
Terminal
.
interface Terminal

A Terminal represents a command-line interface which can read input from a user and display messages to a user.

@since1.0.0

@since1.0.0

Terminal
> =
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<number, PlatformError | Terminal.QuitException, Terminal.Terminal>> | YieldWrap<Effect.Effect<string, PlatformError | Terminal.QuitException, Terminal.Terminal>> | YieldWrap<...>, number>(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* () {
const
const input: string
input
= yield*
const prompt: Effect.Effect<string, PlatformError | Terminal.QuitException, Terminal.Terminal>
prompt
const
const guess: Option.None<number> | Option.Some<number>
guess
=
const parseGuess: (input: string) => Option.None<number> | Option.Some<number>
parseGuess
(
const input: string
input
)
if (
import Option

@since2.0.0

@since2.0.0

Option
.
const isNone: <number>(self: Option.Option<number>) => self is Option.None<number>

Determine if a Option is a None.

@paramself - The Option to check.

@example

import { Option } from "effect"
assert.deepStrictEqual(Option.isNone(Option.some(1)), false)
assert.deepStrictEqual(Option.isNone(Option.none()), true)

@since2.0.0

isNone
(
const guess: Option.None<number> | Option.Some<number>
guess
)) {
yield*
const display: (message: string) => Effect.Effect<void, PlatformError, Terminal.Terminal>
display
("You must enter an integer from 1 to 100")
return yield*
const answer: Effect.Effect<number, PlatformError | Terminal.QuitException, Terminal.Terminal>
answer
}
return
const guess: Option.Some<number>
guess
.
Some<number>.value: number
value
})
// Check if the guess is too high, too low, or correct
const
const check: <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>) => Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
check
= <
function (type parameter) A in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
A
,
function (type parameter) E in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
E
,
function (type parameter) R in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
R
>(
secret: number
secret
: number,
guess: number
guess
: number,
ok: Effect.Effect<A, E, R>
ok
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

The Effect interface defines a value that 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.

@since2.0.0

@since2.0.0

Effect
<
function (type parameter) A in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
A
,
function (type parameter) E in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
E
,
function (type parameter) R in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
R
>,
ko: Effect.Effect<A, E, R>
ko
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

The Effect interface defines a value that 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.

@since2.0.0

@since2.0.0

Effect
<
function (type parameter) A in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
A
,
function (type parameter) E in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
E
,
function (type parameter) R in <A, E, R>(secret: number, guess: number, ok: Effect.Effect<A, E, R>, ko: Effect.Effect<A, E, R>): Effect.Effect<A, PlatformError | E, Terminal.Terminal | R>
R
>
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, PlatformError, Terminal.Terminal>> | YieldWrap<Effect.Effect<A, E, R>>, A>(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* () {
if (
guess: number
guess
>
secret: number
secret
) {
yield*
const display: (message: string) => Effect.Effect<void, PlatformError, Terminal.Terminal>
display
("Too high")
return yield*
ko: Effect.Effect<A, E, R>
ko
} else if (
guess: number
guess
<
secret: number
secret
) {
yield*
const display: (message: string) => Effect.Effect<void, PlatformError, Terminal.Terminal>
display
("Too low")
return yield*
ko: Effect.Effect<A, E, R>
ko
} else {
return yield*
ok: Effect.Effect<A, E, R>
ok
}
})
// End the game with a success message
const
const end: Effect.Effect<void, PlatformError, Terminal.Terminal>
end
=
const display: (message: string) => Effect.Effect<void, PlatformError, Terminal.Terminal>
display
("You guessed it!")
// Main game loop
const
const loop: (secret: number) => Effect.Effect<void, Terminal.QuitException | PlatformError, Terminal.Terminal>
loop
= (
secret: number
secret
: number
):
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

The Effect interface defines a value that 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.

@since2.0.0

@since2.0.0

Effect
<
void,
import Terminal
Terminal
.
class QuitException

A QuitException represents an exception that occurs when a user attempts to quit out of a Terminal prompt for input (usually by entering ctrl+c).

@since1.0.0

QuitException
|
type PlatformError = BadArgument | SystemError

@since1.0.0

@since1.0.0

PlatformError
,
import Terminal
Terminal
.
interface Terminal

A Terminal represents a command-line interface which can read input from a user and display messages to a user.

@since1.0.0

@since1.0.0

Terminal
> =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, PlatformError | Terminal.QuitException, Terminal.Terminal>>, void>(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* () {
const
const guess: number
guess
= yield*
const answer: Effect.Effect<number, PlatformError | Terminal.QuitException, Terminal.Terminal>
answer
return yield*
const check: <void, PlatformError | Terminal.QuitException, Terminal.Terminal>(secret: number, guess: number, ok: Effect.Effect<void, PlatformError | Terminal.QuitException, Terminal.Terminal>, ko: Effect.Effect<...>) => Effect.Effect<...>
check
(
secret: number
secret
,
const guess: number
guess
,
const end: Effect.Effect<void, PlatformError, Terminal.Terminal>
end
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const suspend: <void, PlatformError | Terminal.QuitException, Terminal.Terminal>(effect: LazyArg<Effect.Effect<void, PlatformError | Terminal.QuitException, Terminal.Terminal>>) => Effect.Effect<...>

Delays the creation of an Effect until it is actually needed.

When to Use

Use suspend when you need to defer the evaluation of an effect until it is required. This is particularly useful for optimizing expensive computations, managing circular dependencies, or resolving type inference issues.

Details

suspend takes a thunk that represents the effect and wraps it in a suspended effect. This means the effect will not be created until it is explicitly needed, which is helpful in various scenarios:

  • Lazy Evaluation: Helps optimize performance by deferring computations, especially when the effect might not be needed, or when its computation is expensive. This also ensures that any side effects or scoped captures are re-executed on each invocation.
  • Handling Circular Dependencies: Useful in managing circular dependencies, such as recursive functions that need to avoid eager evaluation to prevent stack overflow.
  • Unifying Return Types: Can help TypeScript unify return types in situations where multiple branches of logic return different effects, simplifying type inference.

@example

// Title: Lazy Evaluation with Side Effects
import { Effect } from "effect"
let i = 0
const bad = Effect.succeed(i++)
const good = Effect.suspend(() => Effect.succeed(i++))
console.log(Effect.runSync(bad)) // Output: 0
console.log(Effect.runSync(bad)) // Output: 0
console.log(Effect.runSync(good)) // Output: 1
console.log(Effect.runSync(good)) // Output: 2

@example

// Title: Recursive Fibonacci import { Effect } from "effect"

const blowsUp = (n: number): Effect.Effect => n < 2 ? Effect.succeed(1) : Effect.zipWith(blowsUp(n - 1), blowsUp(n - 2), (a, b) => a + b)

// console.log(Effect.runSync(blowsUp(32))) // crash: JavaScript heap out of memory

const allGood = (n: number): Effect.Effect => n < 2 ? Effect.succeed(1) : Effect.zipWith( Effect.suspend(() => allGood(n - 1)), Effect.suspend(() => allGood(n - 2)), (a, b) => a + b )

console.log(Effect.runSync(allGood(32))) // Output: 3524578

@example

// Title: Using Effect.suspend to Help TypeScript Infer Types import { Effect } from "effect"

// Without suspend, TypeScript may struggle with type inference. // Inferred type: // (a: number, b: number) => // Effect<never, Error, never> | Effect<number, never, never> const withoutSuspend = (a: number, b: number) => b === 0 ? Effect.fail(new Error("Cannot divide by zero")) : Effect.succeed(a / b)

// Using suspend to unify return types. // Inferred type: // (a: number, b: number) => Effect<number, Error, never> const withSuspend = (a: number, b: number) => Effect.suspend(() => b === 0 ? Effect.fail(new Error("Cannot divide by zero")) : Effect.succeed(a / b) )

@since2.0.0

suspend
(() =>
const loop: (secret: number) => Effect.Effect<void, Terminal.QuitException | PlatformError, Terminal.Terminal>
loop
(
secret: number
secret
))
)
})
// Full game setup and execution
const
const game: Effect.Effect<void, PlatformError | Terminal.QuitException, Terminal.Terminal>
game
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, PlatformError | Terminal.QuitException, Terminal.Terminal>>, void>(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*
const display: (message: string) => Effect.Effect<void, PlatformError, Terminal.Terminal>
display
(
`We have selected a random number between 1 and 100.
See if you can guess it in 10 turns or fewer.
We'll tell you if your guess was too high or too low.`
)
yield*
const loop: (secret: number) => Effect.Effect<void, Terminal.QuitException | PlatformError, Terminal.Terminal>
loop
(yield*
const secret: Effect.Effect<number, never, never>
secret
)
})
// Run the game
import NodeRuntime
NodeRuntime
.
const runMain: RunMain
<PlatformError | Terminal.QuitException, void>(effect: Effect.Effect<void, PlatformError | Terminal.QuitException, never>, options?: {
readonly disableErrorReporting?: boolean | undefined;
readonly disablePrettyLogger?: boolean | undefined;
readonly teardown?: Teardown | undefined;
}) => void (+1 overload)
runMain
(
const game: Effect.Effect<void, PlatformError | Terminal.QuitException, Terminal.Terminal>
game
.
Pipeable.pipe<Effect.Effect<void, PlatformError | Terminal.QuitException, Terminal.Terminal>, Effect.Effect<void, PlatformError | Terminal.QuitException, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Terminal.Terminal, never, never>(layer: Layer<Terminal.Terminal, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<...> (+9 overloads)

Provides the necessary Layers to an effect, removing its dependency on the environment.

You can pass multiple layers, a Context, Runtime, or ManagedRuntime to the effect.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import NodeTerminal
NodeTerminal
.
const layer: Layer<Terminal.Terminal, never, never>

@since1.0.0

layer
)))