Effect.ts: Absence as First-Class
Dependency Injection • Lesson 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