What does the type signature Effect<A, E, R> represent?
Effect<A, E, R>: A = success type, E = failure type (typed, not thrown), R = required services/context (the environment). Unlike Promise, Effects are lazy and composable — they describe a computation without running it. Run with Effect.runPromise or Effect.runSync. The typed error channel eliminates silent exception handling.
2 / 5
How does Effect.gen() improve Effect composition compared to pipe()?
Effect.gen(): Example: Effect.gen(function* (_) { const user = yield* _(fetchUser(id)); const posts = yield* _(fetchPosts(user.id)); return { user, posts }; }). The generator syntax reads like async/await but preserves the full Effect type including error and context channels. _ is a helper that correctly types the yielded values.
3 / 5
What is a Layer in the Effect-TS framework?
Layer: in Effect-TS implements dependency injection. Layer.effect(DatabaseService, createDbConnection) constructs the DatabaseService using an Effect. Layers compose: Layer.provide(ServiceA, ServiceBLayer). At app startup, you provide the full layer stack to resolve all dependencies. Layers support resource management via Scope for proper cleanup.
4 / 5
What is the purpose of pipe() in Effect-TS?
pipe():pipe(effect, Effect.map(f), Effect.flatMap(g), Effect.catchAll(h)) reads left-to-right. Without pipe: Effect.catchAll(Effect.flatMap(Effect.map(effect, f), g), h) — deeply nested and hard to read. Effect-TS exports pipe from the effect package and all Effect combinators are designed to be used in pipe chains.
5 / 5
How does Effect-TS handle typed errors differently from try/catch?
Typed errors: In vanilla TypeScript, try { await fetch() } catch (e: unknown) — e is unknown. In Effect-TS, Effect<User, NetworkError | ParseError, never> — the compiler knows exactly what errors are possible. Use Effect.catchTag('NetworkError', handler) to handle specific error types. Unhandled errors remain in the E channel and prevent running the Effect.