Effect.ts: Absence as First-Class

Dependency InjectionLesson 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