| title | Use .pipe for Composition | ||||
|---|---|---|---|---|---|
| id | use-pipe-for-composition | ||||
| skillLevel | beginner | ||||
| applicationPatternId | core-concepts | ||||
| summary | Use the .pipe() method to chain multiple operations onto an Effect in a readable, top-to-bottom sequence. | ||||
| tags |
|
||||
| rule |
|
||||
| related |
|
||||
| author | Dillon Mulroy | ||||
| lessonOrder | 23 |
To apply a sequence of transformations or operations to an Effect, use the
.pipe() method.
Piping makes code readable and avoids deeply nested function calls. It allows you to see the flow of data transformations in a clear, linear fashion.
import { Effect } from "effect";
const program = Effect.succeed(5).pipe(
Effect.map((n) => n * 2),
Effect.map((n) => `The result is ${n}`),
Effect.tap(Effect.log)
);
// Demonstrate various pipe composition patterns
const demo = Effect.gen(function* () {
yield* Effect.log("=== Using Pipe for Composition Demo ===");
// 1. Basic pipe composition
yield* Effect.log("\n1. Basic pipe composition:");
yield* program;
// 2. Complex pipe composition with multiple transformations
yield* Effect.log("\n2. Complex pipe composition:");
const complexResult = yield* Effect.succeed(10).pipe(
Effect.map((n) => n + 5),
Effect.map((n) => n * 2),
Effect.tap((n) => Effect.log(`Intermediate result: ${n}`)),
Effect.map((n) => n.toString()),
Effect.map((s) => `Final: ${s}`)
);
yield* Effect.log("Complex result: " + complexResult);
// 3. Pipe with flatMap for chaining effects
yield* Effect.log("\n3. Pipe with flatMap for chaining effects:");
const chainedResult = yield* Effect.succeed("hello").pipe(
Effect.map((s) => s.toUpperCase()),
Effect.flatMap((s) => Effect.succeed(`${s} WORLD`)),
Effect.flatMap((s) => Effect.succeed(`${s}!`)),
Effect.tap((s) => Effect.log(`Chained: ${s}`))
);
yield* Effect.log("Chained result: " + chainedResult);
// 4. Pipe with error handling
yield* Effect.log("\n4. Pipe with error handling:");
const errorHandledResult = yield* Effect.succeed(-1).pipe(
Effect.flatMap((n) =>
n > 0 ? Effect.succeed(n) : Effect.fail(new Error("Negative number"))
),
Effect.catchAll((error) =>
Effect.succeed("Handled error: " + error.message)
),
Effect.tap((result) => Effect.log(`Error handled: ${result}`))
);
yield* Effect.log("Error handled result: " + errorHandledResult);
// 5. Pipe with multiple operations
yield* Effect.log("\n5. Pipe with multiple operations:");
const multiOpResult = yield* Effect.succeed([1, 2, 3, 4, 5]).pipe(
Effect.map((arr) => arr.filter((n) => n % 2 === 0)),
Effect.map((arr) => arr.map((n) => n * 2)),
Effect.map((arr) => arr.reduce((sum, n) => sum + n, 0)),
Effect.tap((sum) => Effect.log(`Sum of even numbers doubled: ${sum}`))
);
yield* Effect.log("Multi-operation result: " + multiOpResult);
yield* Effect.log("\n✅ Pipe composition demonstration completed!");
});
Effect.runPromise(demo);Explanation:
Using .pipe() allows you to compose operations in a top-to-bottom style,
improving readability and maintainability.
Nesting function calls manually. This is hard to read and reorder.
Effect.tap(Effect.map(Effect.map(Effect.succeed(5), n => n * 2), n => ...))