Effect.ts: Absence as First-Class

Data TypesLesson 39 of 51

39. Either.flatMap - Short-Circuiting Errors

Like Option, but failures carry context about WHY absence happened

Code Example
const parseUser = (data: unknown): Either<User, string> => {
  if (!data) return Either.left("No data");
  // ... parse logic
  return Either.right(user);
};

const validateAge = (user: User): Either<User, string> => {
  if (user.age < 18) return Either.left("Too young");
  return Either.right(user);
};

const process = parseUser(data).pipe(
  Either.flatMap(user => validateAge(user))
);

// Either<User, string>
// Right(user): both steps succeeded
// Left("No data"): failed at parse
// Left("Too young"): failed at validation
Interactive Example
const { Either } = await import('effect');
const parseUser = (data) => data ? Either.right({ age: 25 }) : Either.left('No data');
const validateAge = (user) => user.age >= 18 ? Either.right(user) : Either.left('Too young');
const r1 = parseUser(true).pipe(
      Either.flatMap(user => validateAge(user))
);
const r2 = parseUser(false).pipe(
      Either.flatMap(user => validateAge(user))
);
const m1 = Either.match(r1, { onLeft: e => 'Error: ' + e, onRight: u => 'Success (age ' + u.age + ')' });
const m2 = Either.match(r2, { onLeft: e => 'Error: ' + e, onRight: u => 'Success' });
return `Either.flatMap!

Valid: ${m1}
Invalid: ${m2}

✓ Contextual errors!`;
Explanation

Either.flatMap: propagating contextual absence.

Traditional approach: try/catch, lose context. Either approach:

  • Parse might fail (typed absence with reason)
  • Validate might fail (typed absence with reason)
  • No assumptions about success
  • First failure short-circuits
  • Error context preserved

Absence-first error chains: know exactly WHERE and WHY absence occurred!


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