Effect-TS: English for Functional Programming Patterns in TypeScript
Learn the English vocabulary for Effect-TS — pipe, gen, Layer, Service, Schedule, and error handling — for ESL TypeScript engineers adopting functional patterns.
Effect-TS is a TypeScript library for writing production-grade, type-safe applications using functional programming patterns. It provides a structured approach to handling errors, managing dependencies, and controlling side effects. The vocabulary in this post is aimed at ESL developers who want to read Effect documentation fluently, participate in code reviews, and explain functional concepts in English to their teammates.
The Effect Type and Core Primitives
Effect type — the central abstraction in Effect-TS, representing a computation that may succeed with a value, fail with a typed error, or require services from the environment; written as Effect.Effect<Success, Error, Requirements>.
“Every database call in our service is wrapped in the Effect type so the compiler forces us to handle both the success case and every possible failure mode.”
succeed — a function that creates an Effect that immediately produces a value without performing any side effects; the equivalent of Promise.resolve in effect-oriented code.
“We use Effect.succeed(cachedUser) when the user is already in memory to avoid hitting the database.”
fail — a function that creates an Effect representing a typed failure; unlike throwing an exception, the failure type is tracked in the Effect’s type signature and must be handled explicitly.
“When the user is not found, we return Effect.fail(new UserNotFoundError(id)) so the compiler ensures every caller addresses this error case.”
Composition
pipe — a function that takes a value and passes it through a series of transformations in left-to-right order; it is the primary way to compose Effect operations without deep nesting.
“We use pipe to chain the database query, the permission check, and the response transformation into a single readable expression.”
gen function — a generator-based syntax (Effect.gen) that lets you write sequential Effect code using yield, making it look similar to async/await while preserving full type safety.
“The team prefers the gen function style because new members find it easier to read than deeply nested pipe chains.”
match — an operator that handles both the success and failure channels of an Effect in a single step, similar to a typed switch statement over the result.
“We use Effect.match to convert the typed error into an HTTP status code and body before sending the response to the client.”
Error Handling
catchAll — an operator that catches any failure in an Effect and runs a recovery function, allowing the pipeline to continue rather than propagating the error.
“We added catchAll at the boundary of the payment service to log the error and return a fallback response when the payment provider is unavailable.”
tagged error — an error class with a readonly _tag property that lets Effect-TS distinguish between different failure types in a union; essential for exhaustive error handling.
“By using tagged errors, the compiler tells us exactly which error variants the catchAll handler needs to address.”
defect — an unexpected, unrecoverable error (such as a programming mistake or an out-of-memory condition) that Effect treats separately from expected typed failures; defects propagate to the top level and crash the fiber.
“We reserved defects for truly unexpected conditions and used typed failures for any error a caller might reasonably want to recover from.”
Dependency Injection
Service — an interface declared with Context.Tag that represents a capability your Effect code needs, such as a database client or an email sender; services are provided at the application boundary.
“We declared an EmailService interface and used it throughout the order confirmation logic without importing any concrete implementation.”
Layer — a description of how to construct one or more services and their dependencies; Layers are composed together to form the full dependency graph of your application.
“The production Layer wires up the real database client, while the test Layer substitutes an in-memory implementation so tests run without a real database connection.”
provide — the operation that satisfies an Effect’s service requirements by supplying a Layer or a concrete service value, producing an Effect that requires nothing from the environment.
“We call Effect.provide(AppLayer) at the application entry point to inject all services and produce a self-contained Effect we can run.”
Scheduling and Retries
Schedule — a reusable policy that describes when and how often to repeat or retry an Effect, including exponential backoff, jitter, and maximum attempt counts.
“We attached a Schedule with exponential backoff to the external API call so transient network errors are retried up to five times before the Effect fails permanently.”
Practice
Find an Effect-TS example that uses both pipe and Layer. Try rewriting the same logic using the gen function style. In English, explain to a colleague why using tagged errors instead of plain JavaScript exceptions makes the codebase easier to maintain over time.