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