Rust-style Result type for type-safe error handling with pattern matching
dart pub add philiprehberger_result_type
Rust-style Result type for type-safe error handling with pattern matching
Add to your pubspec.yaml:
dependencies:
philiprehberger_result_type: ^0.4.0
Then run:
dart pub get
import 'package:philiprehberger_result_type/philiprehberger_result_type.dart';
Result<int, String> divide(int a, int b) {
if (b == 0) return Result.err('Division by zero');
return Result.ok(a ~/ b);
}
final result = divide(10, 2);
final message = result.when(
ok: (value) => 'Result: $value',
err: (error) => 'Error: $error',
);
print(message); // Result: 5
A positional alternative to when() for terser destructuring.
final message = divide(10, 2).fold(
(value) => 'Result: $value',
(error) => 'Error: $error',
);
Swap the Ok and Err variants — useful for inverting validation results.
final swapped = Result<int, String>.ok(42).swap();
print(swapped); // Err(42)
final inverted = Result<int, String>.err('missing').swap();
print(inverted); // Ok(missing)
// Map success values
final doubled = Result<int, String>.ok(5).map((v) => v * 2);
print(doubled); // Ok(10)
// Chain operations
final chained = Result<int, String>.ok(10)
.flatMap((v) => v > 0 ? Result.ok(v) : Result.err('must be positive'));
// Transform errors
final mapped = Result<int, String>.err('not found')
.mapErr((e) => 'Error: $e');
final result = await Result.tryAsync(
() async => fetchDataFromApi(),
(error, stack) => 'Request failed: $error',
);
final results = [Result<int, String>.ok(1), Result.ok(2), Result.ok(3)];
final collected = Result.collect(results);
print(collected); // Ok([1, 2, 3])
final mixed = [Result<int, String>.ok(1), Result.err('bad')];
final failed = Result.collect(mixed);
print(failed); // Err(bad)
final ok = Result<int, String>.ok(42);
print(ok.unwrap()); // 42
print(ok.unwrapOr(0)); // 42
final err = Result<int, String>.err('fail');
print(err.unwrapOr(0)); // 0
// err.unwrap(); // throws StateError
final result = Err<int, String>('missing');
final value = result.unwrapOrElse((e) => e.length);
print(value); // 7
final result = Result<int, String>.ok(42);
print(result.expect('value must exist')); // 42
// On Err, throws StateError with custom message:
// Result<int, String>.err('fail').expect('value must exist');
final result = Result.trySync(
() => int.parse('42'),
(error) => 'parse failed: $error',
);
print(result); // Ok(42)
final result = Result<int, String>.ok(5)
.filter((v) => v > 0, (v) => 'expected positive, got $v');
print(result); // Ok(5)
final filtered = Result<int, String>.ok(-1)
.filter((v) => v > 0, (v) => 'expected positive, got $v');
print(filtered); // Err(expected positive, got -1)
final nested = Result<Result<int, String>, String>.ok(Result.ok(42));
final flat = Result.flatten(nested);
print(flat); // Ok(42)
final nestedErr = Result<Result<int, String>, String>.err('outer error');
final flatErr = Result.flatten(nestedErr);
print(flatErr); // Err(outer error)
final a = Result<int, String>.ok(1);
final b = Result<int, String>.ok(2);
final zipped = Result.zip(a, b);
print(zipped); // Ok((1, 2))
| Method | Description |
|---|---|
Result.ok(T value) | Create a success result |
Result.err(E error) | Create a failure result |
isOk | Whether this is an Ok result |
isErr | Whether this is an Err result |
okOrNull | Success value or null |
errOrNull | Error value or null |
unwrap() | Get value or throw StateError |
unwrapOr(T default) | Get value or return default |
unwrapOrElse(T Function(E) fn) | Get value or compute default from error |
expect(String message) | Get value or throw StateError with message |
map(U Function(T) f) | Transform success value |
mapErr(F Function(E) f) | Transform error value |
flatMap(Result<U,E> Function(T) f) | Chain Result-producing operation |
filter(predicate, orElse) | Keep Ok if predicate passes, else convert to Err |
when({ok, err}) | Exhaustive pattern match |
fold(onOk, onErr) | Reduce to a single value using positional callbacks |
swap() | Convert Ok↔Err |
Result.trySync(fn, onError) | Wrap sync operation into Result |
Result.tryAsync(fn, onError) | Wrap async operation into Result |
Result.collect(results) | Combine list of Results |
Result.flatten(nested) | Unwrap nested Result<Result<T,E>,E> into Result<T,E> |
Result.zip(a, b) | Combine two Results into a record |
dart pub get
dart analyze --fatal-infos
dart test
If you find this project useful: