Composing Effects
Chain and combine effects with pipe and generators.
Composing Effects is a free TypeScript Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Composing Effects
Effects are values, so you build programs by composing them. The core tools are Effect.pipe, Effect.map, Effect.flatMap, and the generator-based Effect.gen syntax.
pipe: Threading Through Functions
pipe passes an effect through a series of transformations left to right, avoiding deep nesting.
import { Effect, pipe } from "effect";
const program = pipe(
Effect.succeed(2),
Effect.map((n) => n + 1),
Effect.map((n) => n * 10)
);
// Effect<number, never, never> producing 30map: Transforming the Success Value
Effect.map applies a pure function to the success value, leaving error and requirement channels untouched.
import { Effect } from "effect";
const doubled = Effect.map(Effect.succeed(21), (n) => n * 2);
// Effect<number, never, never>flatMap: Sequencing Effects
When the next step is itself an effect, use flatMap (also called chain). It runs the first effect, then feeds its value into a function returning another effect.
import { Effect, pipe } from "effect";
const getId = Effect.succeed(1);
const loadUser = (id: number) => Effect.succeed({ id, name: "Ada" });
const program = pipe(getId, Effect.flatMap(loadUser));
// Effect<{ id: number; name: string }, never, never>map vs flatMap
Use map when your function returns a plain value; use flatMap when it returns an effect. Using map with an effect-returning function leaves you with a nested effect.
Channels Accumulate
As you sequence effects, their error types union together and their requirements union together. The composed type reflects everything that can fail and everything that is needed.
// Effect<A, E1, R1> then Effect<B, E2, R2>
// => Effect<B, E1 | E2, R1 | R2>Effect.gen: Generator Syntax
Effect.gen lets you write sequential effect code that reads like async/await, using yield* to unwrap each effect.
import { Effect } from "effect";
const program = Effect.gen(function* () {
const id = yield* Effect.succeed(1);
const user = yield* Effect.succeed({ id, name: "Ada" });
return user.name;
});
// Effect<string, never, never>gen vs pipe
gen is clearer for linear, multi-step flows with intermediate variables; pipe shines for short transformation chains. They interoperate freely.
Combining Independent Effects
Effect.all runs multiple effects and collects their results, accumulating errors and requirements from all of them.
import { Effect } from "effect";
const both = Effect.all([Effect.succeed(1), Effect.succeed("x")]);
// Effect<[number, string], never, never>Still Lazy
All of this only describes the program. Nothing executes until you run it at the edge with Effect.runPromise or Effect.runSync.
import { Effect } from "effect";
// const result = await Effect.runPromise(program);Why This Matters
Composition is what makes effects practical: you assemble small, typed pieces into large programs while the compiler tracks every error and dependency. map, flatMap, pipe, and gen are the everyday verbs of Effect code.
Quick Check
Check your understanding of composing effects.
Recap
You compose effects with map (transform success values), flatMap (sequence effect-returning steps), pipe (thread through transformations), and Effect.gen (await-like generator syntax). Error and requirement channels accumulate as unions, and nothing runs until you execute at the edge.
Frequently asked questions
Is the “Composing Effects” lesson free?
Yes — the full text of “Composing Effects” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.
What will I learn in “Composing Effects”?
Chain and combine effects with pipe and generators. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start TypeScript Academy?
No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Composing Effects” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this TypeScript Academy lesson?
Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.