result_handler

Dart Result Handling Library

Dart Pub Version Pub Likes Pub Publisher Pub Points Pub Monthly Downloads License

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.

Features

Usage

Here’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'),
  );
}

API

Result<E, T> (Abstract Class)

Represents the result of an operation, which can be either a Success<E, T> or a Failure<E, T>.

Core Methods

Value Access Methods

Type Checking

Side Effects

Error Recovery

Filtering

Combining Results

Static Factory Methods

Success<E, T> (Class)

Represents a successful result, holding a value of type T.

Failure<E, T> (Class)

Represents a failed result, holding an error of type E.

Unit (Class)

Represents a unit type for operations that complete successfully but don’t return meaningful values.

License

This library is licensed under the MIT License. See the LICENSE file for more details.

Changelog

See the CHANGELOG.md file for a detailed history of changes.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.