Effect.ts: Absence as First-Class
Dependency Injection • Lesson 20 of 51
20. Layers - Building Dependencies
Layers are recipes for creating services. They compose like Effects!
Code Example
// Service definitions
class Config extends Context.Tag("Config")<...>() {}
class Database extends Context.Tag("Database")<...>() {}
class Logger extends Context.Tag("Logger")<...>() {}
// Layer: recipe for making Database
const DatabaseLive = Layer.effect(
Database,
Effect.gen(function* () {
const config = yield* Config; // Needs Config!
const logger = yield* Logger; // Needs Logger!
return makeDatabaseClient(config, logger);
})
);
// Type: Layer<Database, never, Config | Logger>
// ^^^^^^^^ ^^^^^^^^^^^^^^^^
// Provides Requires these!
// Compose layers
const AppLive = Layer.mergeAll(
ConfigLive,
LoggerLive,
DatabaseLive // Will use Config & Logger
);
Interactive Example
const output: string[] = [];
output.push('Layer<Database, never, Config | Logger>');
output.push(' ^^^^^^^^ ^^^^^^^^^^^^^^^');
output.push(' Provides Requires');
output.push('');
output.push('Layers compose like Effects!');
output.push('');
output.push('const AppLive = Layer.mergeAll(');
output.push(' ConfigLive,');
output.push(' LoggerLive,');
output.push(' DatabaseLive // Auto-wired!');
output.push(')');
output.push('');
output.push(' Dependency graph built automatically!');
return output.join('
');
Explanation
Layers: describing HOW to build absent services.
Traditional approach: construct dependencies manually. Layer types service construction as absence:
- Database is unavailable
- Config & Logger are ALSO unavailable (Database needs them)
- No assumptions about construction order
- Describe: "HOW to make Database from unavailable Config & Logger"
Absence-first construction: building unavailable things from other unavailable things!
Part 20 of 51 in the Effect.ts Absence Modeling series