A simple and powerful library for handling results (successes and failures) in Dart, inspired by Either from functional programming libraries like dartz. This library uses Success and Failure classes to represent outcomes.
map, mapFailure, flatMap, bind and when for chaining and transforming results in a concise and readable way.getOrElse and getOrThrow for gracefully handle errorsisSuccess/isFailure getters and safe value access with getOrNull/getErrorOrNulltap and tapError methodsorElse methodfilterOrElse methodsequence static methodtryCatch, tryCatchAsync, and fromNullablezipWith methodUnit type for operations that don’t return meaningful valuesHere’s how to use the library:
import 'package:result_handler/result_handler.dart';
// Using the new tryCatchAsync factory method
Future<Result<String, int>> fetchData() async {
return Result.tryCatchAsync(
() async {
await Future.delayed(const Duration(seconds: 1)); // Simulate work
if (DateTime.now().second % 2 == 0) {
return 42; // Success case
} else {
throw Exception("Data fetch failed"); // This will be caught
}
},
(error, stackTrace) => "Network error: ${error.toString()}",
);
}
// Example of a validation function
Result<String, int> validateAge(int? age) {
return Result.fromNullable(age, () => "Age cannot be null")
.filterOrElse(
(value) => value >= 0 && value <= 150,
(value) => "Invalid age: $value",
);
}
void main() async {
final result = await fetchData();
// Basic pattern matching
result.when(
success: (value) => print('Success: $value'),
failure: (error) => print('Error: $error'),
);
// Using convenience getters
if (result.isSuccess) {
print('Operation succeeded with value: ${result.getOrNull()}');
}
// Chain operations with tap for side effects
final processedResult = result
.tap((value) => print('Processing value: $value')) // Side effect
.map((value) => value * 2)
.tapError((error) => print('Logging error: $error')); // Error side effect
// Error recovery
final recoveredResult = result.orElse((error) => Success(0));
print('Recovered value: ${recoveredResult.getOrElse((_) => -1)}');
// Working with multiple results
final results = [Success<String, int>(1), Success<String, int>(2), Success<String, int>(3)];
final sequenceResult = Result.sequence(results);
sequenceResult.when(
success: (values) => print('All values: $values'),
failure: (error) => print('One failed: $error'),
);
// Combining results
final result1 = Success<String, int>(10);
final result2 = Success<String, int>(20);
final combined = result1.zipWith(result2, (a, b) => a + b);
print('Combined: ${combined.getOrElse((_) => 0)}');
// Validation example
final ageValidation = validateAge(25);
ageValidation.when(
success: (age) => print('Valid age: $age'),
failure: (error) => print('Validation error: $error'),
);
// Using Unit for operations without meaningful return values
final saveResult = Result.tryCatch<String, Unit>(
() {
// Simulate a save operation
print('Saving data...');
return const Unit();
},
(error, stackTrace) => 'Save failed: ${error.toString()}',
);
saveResult.when(
success: (_) => print('Save completed successfully'),
failure: (error) => print('Save failed: $error'),
);
}
Result<E, T> (Abstract Class)Represents the result of an operation, which can be either a Success<E, T> or a Failure<E, T>.
bind<R>(Result<E, R> Function(T value) transform): Binds a function to the Result.flatMap<R>(Result<E, R> Function(T value) transform): Similar to map but the transformation returns another Result.map<R>(R Function(T value) transform): Transforms the value inside a Success, otherwise does nothing.mapFailure<R>(R Function(E error) transform): Transforms the error inside a Failure, otherwise does nothing.when<R>({required R Function(T data) success, required R Function(E error) failure}): Executes the success callback if it’s a Success or failure if it’s a Failure.getOrElse(T Function(E error) orElse): Returns the value if it’s a Success, otherwise returns the result of the orElse callback.getOrThrow(): Returns the value if it’s a Success, otherwise throws the error.getOrNull(): Returns the value if it’s a Success, otherwise returns null.getErrorOrNull(): Returns the error if it’s a Failure, otherwise returns null.isSuccess: Returns true if this is a Success.isFailure: Returns true if this is a Failure.tap(void Function(T value) fn): Executes a function with the success value for side effects.tapError(void Function(E error) fn): Executes a function with the error value for side effects.orElse(Result<E, T> Function(E error) recoveryFn): Attempts to recover from a failure.filterOrElse(bool Function(T value) predicate, E Function(T value) errorIfFalse): Filters success values based on a predicate.zipWith<U, R>(Result<E, U> other, R Function(T a, U b) combiner): Combines this result with another result.Result.fromNullable<E, T>(T? value, E Function() errorIfNull): Creates a Result from a nullable value.Result.tryCatch<E, T>(T Function() fn, E Function(Object error, StackTrace stackTrace) onError): Safely executes a function and wraps the result.Result.tryCatchAsync<E, T>(Future<T> Function() fn, E Function(Object error, StackTrace stackTrace) onError): Safely executes an async function and wraps the result.Result.sequence<E, T>(Iterable<Result<E, T>> results): Transforms multiple results into a single result containing a list.Success<E, T> (Class)Represents a successful result, holding a value of type T.
data: The successful value of type T.Result methods with success-specific behavior.toString() representation.Failure<E, T> (Class)Represents a failed result, holding an error of type E.
error: The error value of type E.Result methods with failure-specific behavior.toString() representation.Unit (Class)Represents a unit type for operations that complete successfully but don’t return meaningful values.
Result<E, Unit> when you only care about success/failure, not the return value.Unit instances are considered equal.This library is licensed under the MIT License. See the LICENSE file for more details.
See the CHANGELOG.md file for a detailed history of changes.
Contributions are welcome! Please feel free to submit issues or pull requests.