Console
Wraps console operations in Effect.
The Console service exposes common console methods such as logging,
warnings, errors, groups, counters, tables, and timers. Because console access
goes through a service, programs can use custom console implementations in
tests or other environments. This module also includes scoped helpers that
close console groups or timers automatically.
Accessors
Writes the supplied assertion message to the console as an error when condition is false; when condition is true, no console output is produced.
Signature
declare function assert(condition: boolean, ...args: readonly Array<any>): Effect<void>Example
(Logging failed assertions)
import { Console, Effect } from "effect"
const errors: Array<unknown> = []const testConsole: Console.Console = Object.assign(Object.create(console), { assert: (condition: boolean, ...args: ReadonlyArray<unknown>) => { if (!condition) errors.push(...args) }})const program = Effect.gen(function*() { yield* Console.assert(2 + 2 === 4, "Math is working correctly") yield* Console.assert(2 + 2 === 5, "This will be logged as an error")})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))errors // => ["This will be logged as an error"]Runs the current console service's clear operation.
When to use
Use to request that the active console implementation clear its visible output.
Gotchas
The clearing behavior depends on the active console implementation and host environment.
Signature
declare const clear: Effect.Effect<void>Example
(Clearing console output)
import { Console, Effect } from "effect"
const operations: Array<string> = []const testConsole: Console.Console = Object.assign(Object.create(console), { log: (message: string) => operations.push(`log:${message}`), clear: () => operations.push("clear")})const program = Effect.gen(function*() { yield* Console.log("This will be cleared") yield* Console.clear yield* Console.log("This appears after clearing")})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))operations // => ["log:This will be cleared", "clear", "log:This appears after clearing"]Logs and increments the counter associated with label, using the console's default counter when no label is provided.
Signature
declare function count(label?: string): Effect<void>Example
(Counting repeated calls)
import { Console, Effect } from "effect"
const counters = new Map<string, number>()const messages: Array<string> = []const testConsole: Console.Console = Object.assign(Object.create(console), { count: (label = "default") => { const count = (counters.get(label) ?? 0) + 1 counters.set(label, count) messages.push(`${label}: ${count}`) }})const program = Effect.gen(function*() { yield* Console.count("my-counter") yield* Console.count("my-counter") yield* Console.count()})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))messages // => ["my-counter: 1", "my-counter: 2", "default: 1"]countReset
Resets the counter associated with the specified label back to zero.
Signature
declare function countReset(label?: string): Effect<void>Example
(Resetting a counter)
import { Console, Effect } from "effect"
const counters = new Map<string, number>()const messages: Array<string> = []const testConsole: Console.Console = Object.assign(Object.create(console), { count: (label = "default") => { const count = (counters.get(label) ?? 0) + 1 counters.set(label, count) messages.push(`${label}: ${count}`) }, countReset: (label = "default") => counters.set(label, 0)})const program = Effect.gen(function*() { yield* Console.count("my-counter") yield* Console.count("my-counter") yield* Console.countReset("my-counter") yield* Console.count("my-counter")})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))messages // => ["my-counter: 1", "my-counter: 2", "my-counter: 1"]Writes a debug message through the current Console service.
Details
The arguments are passed to the service's debug method when the returned
Effect is executed. Any filtering behavior depends on the active console
implementation.
Signature
declare function debug(...args: readonly Array<any>): Effect<void>Example
(Writing debug messages)
import { Console, Effect } from "effect"
const messages: Array<ReadonlyArray<unknown>> = []const testConsole: Console.Console = Object.assign(Object.create(console), { debug: (...args: ReadonlyArray<unknown>) => messages.push(args)})const program = Effect.gen(function*() { yield* Console.debug("Debug info:", { userId: 123, action: "login" }) yield* Console.debug("Processing step", 1, "of", 5)})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))messages // => [["Debug info:", { userId: 123, action: "login" }], ["Processing step", 1, "of", 5]]Displays an interactive list of the properties of the specified object, optionally using console-specific inspection options for debugging complex data structures.
Signature
declare function dir(item: any, options?: any): Effect<void>Example
(Inspecting an object)
import { Console, Effect } from "effect"
const inspected: Array<unknown> = []const testConsole: Console.Console = Object.assign(Object.create(console), { dir: (item: unknown, options?: unknown) => inspected.push([item, options])})const program = Effect.gen(function*() { const obj = { name: "John", age: 30, nested: { city: "New York" } } yield* Console.dir(obj) yield* Console.dir(obj, { depth: 2 })})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))const expected = [ [{ name: "John", age: 30, nested: { city: "New York" } }, undefined], [{ name: "John", age: 30, nested: { city: "New York" } }, { depth: 2 }]]inspected // => expectedDisplays an interactive tree of descendant XML or HTML elements, which is particularly useful for inspecting DOM elements in browser environments.
Signature
declare function dirxml(...args: readonly Array<any>): Effect<void>Example
(Inspecting XML-like data)
import { Console, Effect } from "effect"
const messages: Array<unknown> = []const testConsole: Console.Console = Object.assign(Object.create(console), { dirxml: (...args: ReadonlyArray<unknown>) => messages.push(...args)})const program = Effect.gen(function*() { yield* Console.dirxml("<user id=\"1\">Ada</user>")})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))messages // => ["<user id=\"1\">Ada</user>"]Writes an error-level message to the console, typically displayed with error styling by the active console implementation.
Signature
declare function error(...args: readonly Array<any>): Effect<void>Example
(Writing error messages)
import { Console, Effect } from "effect"
const messages: Array<ReadonlyArray<unknown>> = []const testConsole: Console.Console = Object.assign(Object.create(console), { error: (...args: ReadonlyArray<unknown>) => messages.push(args)})const program = Effect.gen(function*() { yield* Console.error("Something went wrong!") yield* Console.error("Error details:", { code: 500, message: "Internal Server Error" })})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))const expected = [ ["Something went wrong!"], ["Error details:", { code: 500, message: "Internal Server Error" }]]messages // => expectedCreates a scoped console group, optionally collapsed and labeled, and closes it automatically when the Effect scope is finalized.
Signature
declare function group(options?: { collapsed?: boolean; label?: string;}): Effect<void, never, Scope>Example
(Grouping scoped output)
import { Console, Effect } from "effect"
const operations: Array<string> = []const testConsole: Console.Console = Object.assign(Object.create(console), { group: (label?: string) => operations.push(`group:${label}`), groupEnd: () => operations.push("groupEnd"), log: (message: string) => operations.push(`log:${message}`)})const program = Effect.gen(function*() { yield* Effect.scoped( Effect.gen(function*() { yield* Console.group({ label: "User Processing" }) yield* Console.log("Loading user data...") yield* Console.log("Validating user...") yield* Console.log("User processed successfully") }) )})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))const expected = [ "group:User Processing", "log:Loading user data...", "log:Validating user...", "log:User processed successfully", "groupEnd"]operations // => expectedWrites an informational message to the console, typically displayed with info styling by the active console implementation.
Signature
declare function info(...args: readonly Array<any>): Effect<void>Example
(Writing informational messages)
import { Console, Effect } from "effect"
const messages: Array<ReadonlyArray<unknown>> = []const testConsole: Console.Console = Object.assign(Object.create(console), { info: (...args: ReadonlyArray<unknown>) => messages.push(args)})const program = Effect.gen(function*() { yield* Console.info("Application started successfully") yield* Console.info("Server configuration:", { port: 3000, env: "development" })})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))const expected = [ ["Application started successfully"], ["Server configuration:", { port: 3000, env: "development" }]]messages // => expectedLogs a general-purpose message to the console.
Signature
declare function log(...args: readonly Array<any>): Effect<void>Example
(Writing log messages)
import { Console, Effect } from "effect"
const messages: Array<ReadonlyArray<unknown>> = []const testConsole: Console.Console = Object.assign(Object.create(console), { log: (...args: ReadonlyArray<unknown>) => messages.push(args)})const program = Effect.gen(function*() { yield* Console.log("Hello, world!") yield* Console.log("User data:", { name: "John", age: 30 }) yield* Console.log("Processing", 42, "items")})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))const expected = [ ["Hello, world!"], ["User data:", { name: "John", age: 30 }], ["Processing", 42, "items"]]messages // => expectedDisplays tabular data as a formatted table in the console, optionally limited to selected properties.
Signature
declare function table(tabularData: any, properties?: readonly Array<string>): Effect<void>Example
(Displaying tabular data)
import { Console, Effect } from "effect"
const calls: Array<unknown> = []const testConsole: Console.Console = Object.assign(Object.create(console), { table: (data: ReadonlyArray<unknown>, properties?: ReadonlyArray<string>) => { calls.push({ rows: data.length, properties }) }})
const program = Effect.gen(function*() { const users = [ { name: "John", age: 30, city: "New York" }, { name: "Jane", age: 25, city: "London" }, { name: "Bob", age: 35, city: "Paris" } ] yield* Console.table(users) yield* Console.table(users, ["name", "age"]) // Only show specific columns})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))calls // => [{ rows: 3, properties: undefined }, { rows: 3, properties: ["name", "age"] }]Starts a scoped timer for label and automatically ends it when the Effect scope is finalized.
Signature
declare function time(label?: string): Effect<void, never, Scope>Example
(Timing scoped work)
import { Console, Effect } from "effect"
const operations: Array<string> = []const testConsole: Console.Console = Object.assign(Object.create(console), { time: (label?: string) => operations.push(`start:${label}`), timeEnd: (label?: string) => operations.push(`end:${label}`), log: (message: string) => operations.push(`log:${message}`)})
const program = Effect.gen(function*() { yield* Effect.scoped( Effect.gen(function*() { yield* Console.time("operation-timer") yield* Console.log("Operation completed") // Timer ends automatically when scope closes }) )})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))operations // => ["start:operation-timer", "log:Operation completed", "end:operation-timer"]Logs the elapsed time for an existing timer without stopping it, allowing progress reports for long-running operations.
Signature
declare function timeLog(label?: string, ...args: readonly Array<any>): Effect<void>Example
(Logging timer progress)
import { Console, Effect } from "effect"
const operations: Array<unknown> = []const testConsole: Console.Console = Object.assign(Object.create(console), { time: (label?: string) => operations.push(["start", label]), timeLog: (label?: string, ...args: ReadonlyArray<unknown>) => operations.push(["log", label, ...args]), timeEnd: (label?: string) => operations.push(["end", label])})
const program = Effect.gen(function*() { yield* Effect.scoped( Effect.gen(function*() { yield* Console.time("long-operation") yield* Console.timeLog("long-operation", "Halfway done") // Timer ends when scope closes }) )})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))operations // => [["start", "long-operation"], ["log", "long-operation", "Halfway done"], ["end", "long-operation"]]Writes the current stack trace to the console to show how the current point in the code was reached.
Signature
declare function trace(...args: readonly Array<any>): Effect<void>Example
(Writing stack traces)
import { Console, Effect } from "effect"
const traces: Array<ReadonlyArray<unknown>> = []const testConsole: Console.Console = Object.assign(Object.create(console), { trace: (...args: ReadonlyArray<unknown>) => traces.push(args)})
const program = Effect.gen(function*() { yield* Console.trace("Debug trace point") yield* Console.trace("Function call:", { functionName: "processData" })})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))traces // => [["Debug trace point"], ["Function call:", { functionName: "processData" }]]Writes a warning-level message to the console, typically displayed with warning styling by the active console implementation.
Signature
declare function warn(...args: readonly Array<any>): Effect<void>Example
(Writing warning messages)
import { Console, Effect } from "effect"
const messages: Array<ReadonlyArray<unknown>> = []const testConsole: Console.Console = Object.assign(Object.create(console), { warn: (...args: ReadonlyArray<unknown>) => messages.push(args)})const program = Effect.gen(function*() { yield* Console.warn("This feature is deprecated") yield* Console.warn("Performance warning:", { slowQuery: "SELECT * FROM large_table" })})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))const expected = [ ["This feature is deprecated"], ["Performance warning:", { slowQuery: "SELECT * FROM large_table" }]]messages // => expectedRuns an Effect inside an optionally labeled or collapsed console group, starting the group before execution and ending it after the Effect completes.
Signature
declare const withGroup: (options?: { readonly collapsed?: boolean; readonly label?: string;}) => <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, R> & <A, E, R>(self: Effect<A, E, R>, options?: { readonly collapsed?: boolean; readonly label?: string;}) => Effect<A, E, R>Example
(Wrapping an effect in a group)
import { Console, Effect } from "effect"
const operations: Array<string> = []const testConsole: Console.Console = Object.assign(Object.create(console), { group: (label?: string) => operations.push(`group:${label}`), groupEnd: () => operations.push("groupEnd"), log: (message: string) => operations.push(`log:${message}`)})const program = Effect.gen(function*() { yield* Console.withGroup( Effect.gen(function*() { yield* Console.log("Step 1: Initialize") yield* Console.log("Step 2: Process") yield* Console.log("Step 3: Complete") }), { label: "Processing Steps", collapsed: false } )})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))const expected = [ "group:Processing Steps", "log:Step 1: Initialize", "log:Step 2: Process", "log:Step 3: Complete", "groupEnd"]operations // => expectedRuns an Effect with a console timer, starting the timer before execution and ending it after the Effect completes.
Signature
declare const withTime: (label?: string) => <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, R> & <A, E, R>(self: Effect<A, E, R>, label?: string) => Effect<A, E, R>Example
(Timing an effect)
import { Console, Effect } from "effect"
const operations: Array<string> = []const testConsole: Console.Console = Object.assign(Object.create(console), { time: (label?: string) => operations.push(`start:${label}`), timeEnd: (label?: string) => operations.push(`end:${label}`), log: (message: string) => operations.push(`log:${message}`)})
const program = Effect.gen(function*() { yield* Console.withTime( Effect.gen(function*() { yield* Console.log("Operation completed") }), "my-operation" )})
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))operations // => ["start:my-operation", "log:Operation completed", "end:my-operation"]Constructors
consoleWith
Creates an Effect that provides access to the current console service and lets you perform operations with it within an Effect context.
Signature
declare function consoleWith<A, E, R>(f: (console: Console) => Effect<A, E, R>): Effect<A, E, R>Example
(Accessing the current console service)
import { Console, Effect } from "effect"
const messages: Array<unknown> = []const testConsole: Console.Console = Object.assign(Object.create(console), { log: (...args: ReadonlyArray<unknown>) => messages.push(...args), error: (...args: ReadonlyArray<unknown>) => messages.push(...args)})const program = Console.consoleWith((console) => Effect.sync(() => { console.log("Hello, world!") console.error("This is an error message") }))
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))messages // => ["Hello, world!", "This is an error message"]Services
Context reference for the current console service in the Effect system, allowing access to the active console implementation from within the Effect context.
When to use
Use when you need an effect to run against a provided console implementation, such as tests or alternate runtimes, rather than the default console.
Details
When no override is provided, the reference resolves to globalThis.console.
See
- consoleWith for using the current console service inside an effect
Signature
declare const Console: Reference<Console>Example
(Accessing the current console)
import { Console, Effect } from "effect"
const messages: Array<unknown> = []const testConsole: Console.Console = Object.assign(Object.create(console), { log: (...args: ReadonlyArray<unknown>) => messages.push(...args)})const program = Console.consoleWith((console) => Effect.sync(() => { console.log("Hello from current console!") }))
Effect.runSync(Effect.provideService(program, Console.Console, testConsole))messages // => ["Hello from current console!"]Represents a console interface for logging, debugging, timing, and grouping output.
Signature
interface Console { assert(condition: boolean, ...args: readonly Array<any>): void; clear(): void; count(label?: string): void; countReset(label?: string): void; debug(...args: readonly Array<any>): void; dir(item: any, options?: any): void; dirxml(...args: readonly Array<any>): void; error(...args: readonly Array<any>): void; group(...args: readonly Array<any>): void; groupCollapsed(...args: readonly Array<any>): void; groupEnd(): void; info(...args: readonly Array<any>): void; log(...args: readonly Array<any>): void; table(tabularData: any, properties?: readonly Array<string>): void; time(label?: string): void; timeEnd(label?: string): void; timeLog(label?: string, ...args: readonly Array<any>): void; trace(...args: readonly Array<any>): void; warn(...args: readonly Array<any>): void;}