Effect.ts: Absence as First-Class

Data TypesLesson 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