name: "using-fpdart" description: "Functional error handling in Dart using the fpdart package with Either, Option, TaskEither, and Do notation. Use when replacing try-catch with type-safe error handling or composing async operations functionally." metadata: last_modified: "2026-04-01 14:35:00 (GMT+8)"
Functional Programming with fpdart
Goal
Implement robust, type-safe, and predictable business logic using functional programming principles. Replace side-effect-prone imperative code with pure functions and composable monads (Option, Either, Task), ensuring that error handling and null-safety are enforced at the type level rather than through runtime exceptions.
Process
Phase 1: Basic Data Containment
Use primitives to handle common edge cases without branching logic:
Option<T>: ReplacesT?. UseOption.of(val)orOption.none(). Access viamatchorgetOrElse.Either<L, R>: Replacestry-catch.L(Left) is for errors,R(Right) is for success.Unit: Replacesvoidto allow functional composition.
Phase 2: Execution & Async Flow
Manage side effects and asynchronous operations through wrappers that defer execution:
IO<T>: Synchronous wrapper for pure/safe side effects.Task<T>: Asynchronous wrapper forFuturethat never fails.TaskEither<L, R>: The standard for API requests. ComposesFutureandEitherinto a single monadic flow.
Phase 3: Advanced Linear Chaining
Utilize the Do Notation to flatten nested flatMap calls into readable, imperative-style blocks while preserving monadic safety:
return TaskEither.Do(($) async {
final user = await $(repository.getUser(id));
final profile = await $(api.getProfile(user.code));
return profile.toDomain();
});
⚡ Quick Reference
Error Handling (Either)
Either<String, int> checkValue(int v) =>
v > 10 ? Either.of(v) : Either.left('Too small');
final result = checkValue(5).match(
(error) => 'Failure: $error',
(value) => 'Success: $value',
);
Async Operations (TaskEither)
TaskEither<Exception, User> fetchUser(String id) =>
TaskEither.tryCatch(
() => api.getUser(id),
(error, stack) => Exception('Fetch failed: $error'),
);
Collections Extension
fpdart extends Iterable with safer methods:
list.head->Option<T>(Safefirst)list.all((e) => ...)->bool
Constraints
- Zero Exceptions: Prohibit the use of
throwfor expected business errors. Force use ofEitherorTaskEither. - Monadic Integrity: Never use
!(bang operator) or force-casts on functional types. Always use safe extraction methods (match,getOrElse). - Linear Logic: Mandatory use of Do notation when chaining more than two monadic operations to prevent "callback hell."
- Immutability First: Combine with
fast_immutable_collectionsfor all state definitions.