Effect.ts: Absence as First-Class

Dependency InjectionLesson 14 of 51

14. Dependencies - Explicit Requirements

Some absences can only be resolved with specific services

Code Example
// This absence needs a Database to resolve
const getUser: Effect<User, DbError, Database> =
  Effect.gen(function* () {
    const db = yield* Database;  // "I need this"
    const user = yield* db.query("SELECT...");
    return user;
  });

// Can't run without providing Database!
// Effect.runPromise(getUser);  //  Type error!

// Must provide it:
Effect.runPromise(
  getUser.pipe(Effect.provide(DatabaseLive))
);
Interactive Example
const output: string[] = [];
output.push('Effect<User, DbError, Database>');
output.push('');
output.push('This effect REQUIRES Database!');
output.push('');
output.push('Cannot run without providing:');
output.push('  Effect.provide(DatabaseLive)');
output.push('');
output.push(' Dependencies are typed as requirements!');
return output.join('
');
Explanation

Dependencies: typing WHAT is required to resolve absence.

Traditional approach: assume dependencies exist (global state, imports). Effect types unavailability of dependencies:

  • User is unavailable
  • Database is ALSO unavailable (requirement)
  • No assumptions about Database existing
  • Type system enforces: "provide Database before resolving User"

Absence all the way down! Even the tools to resolve absence are typed as absent.


Part 14 of 51 in the Effect.ts Absence Modeling series