resx 0.4.1
resx: ^0.4.1 copied to clipboard
Functional error handling for Dart: Result/Option/Validation + AsyncResult, Stream/Iterable utils, and tiny state Loadable.
Resx ⚡️ #
A lightweight and complete functional error-handling toolkit for Dart, featuring Result, Option, Validation, AsyncResult, stream utilities, and a minimal Loadable state.
Tiny, complete, and functional.
English | 中文
Features ✨ #
🚀 High Performance - Optimized for speed and memory efficiency
🔒 Type Safe - Full null safety and strong typing
🔗 Chainable - Fluent API with method chaining
📦 Batch Operations - Process collections efficiently
🎯 Validation - Accumulate multiple errors elegantly
⚡ Async Support - First-class async/await integration
🧩 Extensions - Native Dart type integrations
Core Types 🧠 #
Result<T, E> - Error Handling ✅/❌ #
Type-safe error handling inspired by Rust's Result type.
import 'package:resx/resx.dart';
// Create results
final success = Result.ok(42);
final failure = Result.err('Something went wrong');
// Chain operations
final result = Result.ok(5)
.map((x) => x * 2)
.flatMap((x) => x > 5 ? Result.ok(x) : Result.err('Too small'));
// Handle both cases
final message = result.fold(
(value) => 'Success: $value',
(error) => 'Error: $error',
);
// Exception catching
final parsed = Result.from(() => int.parse('42')); // Ok(42)
final failed = Result.from(() => int.parse('abc')); // Err(FormatException)
// Guards and swap
final guarded = Result.ok(10).ensure((v) => v > 5, 'Too small');
final swapped = Result.ok(1).swap(); // Err(1)
Option<T> - Nullable Values ❓ #
Safe nullable value handling with Some/None variants.
// Create options
final some = Option.some('Hello');
final none = Option<String>.none();
// Safe operations
final result = Option.some('world')
.map((s) => s.toUpperCase())
.filter((s) => s.length > 3)
.unwrapOr('DEFAULT');
// From nullable
String? nullable = getValue();
final option = Option.fromNullable(nullable);
Validation<E, T> - Error Accumulation 🧰 #
Collect multiple validation errors instead of failing fast.
// Built-in validators
final emailValidation = Validators.email('user@example.com', 'Invalid email');
final rangeValidation = Validators.range(25, 18, 65, 'Age out of range');
// Accumulate errors
final userValidation = Validators.notEmpty('John', 'Name required')
.and(Validators.email('invalid-email', 'Email invalid'))
.and(Validators.range(150, 0, 120, 'Age invalid'));
// Result: Invalid(['Email invalid', 'Age invalid'])
AsyncResult<T, E> - Async Operations ⏱️ #
First-class async support for Result operations.
// Create async results
final asyncResult = AsyncResult.ok(42);
final fromFuture = AsyncResult.from(fetchData());
// Chain async operations
final result = await AsyncResult.ok(5)
.map((x) => x * 2)
.flatMap((x) => AsyncResult.ok(x + 1));
// Handle async errors safely
final safeResult = await AsyncResult.from(riskyOperation())
.orElse((error) => AsyncResult.ok('fallback'));
// Guard async values
final ensured = await AsyncResult.ok<int, String>(10)
.ensure((v) => v > 0, 'non-positive');
Dart Extensions 🧩 #
String Extensions 🔤 #
// Parsing with results
final number = '42'.parseInt(); // Ok(42)
final invalid = 'abc'.parseInt(); // Err(FormatException)
// Validation
final email = 'user@example.com'.validateEmail(); // Valid(...)
final url = Validators.url('https://example.com'); // Valid(...)
List, Stream and Nullable Extensions #
final numbers = [1, 2, 3, 4, 5];
final results = numbers.map((x) => x.isEven ? Result.ok(x) : Result.err('odd'));
final combined = Results.sequence(results); // Ok([...]) or first Err
final (oks, errs) = Results.partition(results);
// Stream helpers
final stream = Stream.fromIterable([1,2,3]);
final asResults = stream.toResultStream<Object>();
final collected = await stream.collectToResult<Object>();
Universal and Nullable Conversions 🔁 #
String? nullable = getValue();
final option = nullable.toOption(); // Option<String>
final result = nullable.toResult('Value is null'); // Result<String, String>
// Universal: wrap any value fast
final r1 = 42.ok<String>(); // Result<int, String>::Ok(42)
final r2 = 'boom'.err<int>(); // Result<int, String>::Err('boom')
final o1 = 'hello'.some(); // Option<String>::Some('hello')
Batch Operations 📦 #
// Combine multiple results
final results = [Result.ok(1), Result.ok(2), Result.ok(3)];
final combined = Results.combine(results); // Ok([1, 2, 3])
// Partition successes and errors
final mixed = [Result.ok(1), Result.err('error'), Result.ok(3)];
final (values, errors) = Results.partition(mixed); // ([1, 3], ['error'])
// Applicative operations
final sum = Results.lift2(
Result.ok(2),
Result.ok(3),
(a, b) => a + b,
); // Ok(5)
Advanced Usage 🚀 #
Custom Validators #
// Using built-in predicate helper
final validation = Validators.predicate<String, String>(
'test',
(v) => v.startsWith('prefix_'),
'Must start with prefix_',
); // Invalid(['Must start with prefix_'])
Pattern Matching #
final result = Result.ok(42);
final message = result.match(
(value) => 'Got value: $value',
(error) => 'Got error: $error',
);
Railway-Oriented Programming #
final pipeline = (String input) => Result.ok(input)
.flatMap(validateInput)
.flatMap(processData)
.flatMap(saveToDatabase)
.map(formatResponse);
final result = pipeline('user input');
Performance #
Focused API, minimal indirections, idiomatic Dart sealed classes and extension types. No magic.
Installation #
Add to your pubspec.yaml
:
dependencies:
resx: any
Then run:
dart pub get
Examples #
Check out the example directory for comprehensive usage examples:
- Basic Usage - Core functionality
- Enhanced Features - All features showcase
API Documentation #
Complete API documentation with examples is available at pub.dev.
Contributing #
Contributions are welcome! Please read our contributing guidelines and feel free to submit issues and pull requests.
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Made with 💙 by FlutterCandies