Effect.ts: Absence as First-Class
Data Types • Lesson 38 of 51
38. Option.flatMap - Chaining Maybe-Absences
Each step might fail - absence can propagate through a chain
Code Example
const getUser = (id: string): Option<User> => {
// User might be absent
return Option.fromNullable(db.find(id));
};
const getUserEmail = (user: User): Option<string> => {
// Email might be absent
return Option.fromNullable(user.email);
};
// Chain: if ANY step is absent, whole thing is absent
const email = getUser("123").pipe(
Option.flatMap(user => getUserEmail(user))
);
// email: Option<string>
// Some("alice@example.com") if both present
// None if EITHER is absent
Interactive Example
const { Option } = await import('effect');
const getUser = (id) => id === '1' ? Option.some({ email: 'alice@example.com' }) : Option.none();
const getUserEmail = (user) => Option.fromNullable(user.email);
const email1 = getUser('1').pipe(
Option.flatMap(user => getUserEmail(user))
);
const email2 = getUser('999').pipe(
Option.flatMap(user => getUserEmail(user))
);
return `Option.flatMap!
User '1': ${Option.match(email1, { onNone: () => 'None', onSome: e => e})}
User '999': ${Option.match(email2, { onNone: () => 'None', onSome: e => e})}
Absence propagates!`;
Explanation
Option.flatMap: propagating absence through chains.
Traditional approach: nested null checks:
const user = getUser(id);
if (user && user.email) { ... }
Option approach:
- User might be absent
- Email might be absent
- No assumptions at each step
- flatMap: "resolve first absence, then try second"
- None anywhere → None everywhere
Absence-first chaining: absence is contagious!
Part 38 of 51 in the Effect.ts Absence Modeling series