Result Utils

A lightweight Flutter package that implements the Result pattern for type-safe error handling using Dart's sealed classes. Instead of throwing exceptions, functions can return a FutureResult<T> that is either a Success with a value or an Error with a message.

Based on Flutter's recommended Result pattern.

Features

  • 🎯 Type-safe error handling — Compile-time guarantees with sealed classes
  • 🚀 Simple API — Easy-to-use Success and Error types
  • 🔄 Future integration — Helper function to wrap async operations
  • 📱 Flutter optimized — Lightweight with minimal dependencies
  • ✅ Well-tested — Comprehensive test coverage

Why the Result Pattern?

The Result pattern is a type-safe alternative to exceptions for handling errors. Instead of throwing exceptions (which can be unhandled), functions return a FutureResult<T> that explicitly indicates success or failure.

Benefits

  • Explicit error handling — Errors are part of the function's contract, not hidden
  • No try-catch boilerplate — Cleaner code without nested try-catch blocks
  • Compile-time safety — The compiler ensures you handle all cases (Success/Error)
  • Better control flow — Easier to compose and chain operations

For a detailed explanation, see Flutter's guide on improving control flow with the Result pattern.

Getting started

Add this to your pubspec.yaml:

dependencies:
  result_utils: ^0.0.1

Then run:

flutter pub get

Usage

Creating Results

Return a FutureResult<T> that is either a Success or an Error:

import 'package:result_utils/result_utils.dart';

FutureResult<int> divide(int a, int b) {
  if (b == 0) {
    return FutureResult.error('Division by zero');
  }
  return FutureResult.success(a ~/ b);
}

// Usage
final result = divide(10, 2);
if (result.hasError) {
  print('Error: ${result.error}');
} else {
  print('Result: ${result.value}');
}

Wrapping Async Operations

Use futureToResult to automatically handle exceptions in futures:

Future<String> fetchData() async {
  final response = await http.get(Uri.parse('https://api.example.com/data'));
  if (response.statusCode == 200) {
    return response.body;
  } else {
    throw Exception('Failed to load data');
  }
}

// Convert the future to a result
final result = await futureToResult(fetchData());

if (result.hasError) {
  print('Error: ${result.error}');
} else {
  print('Data: ${result.value}');
}

Checking Results

final result = FutureResult<String>.success('Hello');

// Check for errors
if (result.hasError) {
  // Handle error
  print(result.error);
} else {
  // Access the value
  print(result.value); // 'Hello'
}

API Reference

FutureResult

A sealed class representing either a success or error state.

Factories

  • FutureResult.success(T value) — Create a successful result
  • FutureResult.error(String error) — Create an error result

Getters

  • hasError → bool — Returns true if this is an error
  • error → String — Gets the error message (only use when hasError is true)
  • value → T? — Gets the value (only available on success)

Success

A subclass of FutureResult<T> representing a successful result with a value.

Error

A subclass of FutureResult<T> representing an error with a message.

futureToResult

Converts a Future<T> into a Future<FutureResult<T>>, automatically catching exceptions.

Future<FutureResult<T>> futureToResult<T>(Future<T> future)

Best Practices

  • ✅ Return FutureResult from functions that can fail
  • ✅ Use hasError to check the result before accessing value
  • ✅ Prefer meaningful error messages over generic exceptions
  • ✅ Use futureToResult for all async operations to avoid try-catch boilerplate

See Also

  • neverthrow_dart — A more feature-rich Result pattern implementation with functional methods like .map(), .flatMap(), and .fold(). Choose result_utils if you prefer a lightweight, straightforward API; choose neverthrow_dart if you need advanced functional composition features.

Contributing

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

License

This project is licensed under the MIT License - see the LICENSE file for details.

Libraries

result_utils