{"id":17238365,"url":"https://github.com/hoc081098/dart_either","last_synced_at":"2026-03-07T13:01:04.254Z","repository":{"id":38416641,"uuid":"356366733","full_name":"hoc081098/dart_either","owner":"hoc081098","description":"Either monad for Dart language and Flutter framework. The library for error handling and railway oriented programming. Supports `Monad comprehensions` (both `sync` and `async` versions). Supports `async map` and `async flatMap` hiding the boilerplate of working with asynchronous computations `Future\u003cEither\u003cL, R\u003e\u003e`. Error handler library for type-safe and easy work with errors on Dart and Flutter. Either is an alternative to Nullable value and Exceptions.","archived":false,"fork":false,"pushed_at":"2026-03-05T09:52:26.000Z","size":210,"stargazers_count":9,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-03-05T13:56:53.603Z","etag":null,"topics":["dart","dart-either","dart-either-monad","dart-functional","dart-functional-programming","either","either-dart","either-monad","flutter-functional","functional","functional-programming","pub"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/dart_either","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hoc081098.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2021-04-09T18:37:59.000Z","updated_at":"2026-03-01T08:00:46.000Z","dependencies_parsed_at":"2024-02-27T00:24:22.836Z","dependency_job_id":"c2b9a211-1d8a-4b55-8057-e20459f9fef3","html_url":"https://github.com/hoc081098/dart_either","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/hoc081098/dart_either","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoc081098%2Fdart_either","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoc081098%2Fdart_either/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoc081098%2Fdart_either/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoc081098%2Fdart_either/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hoc081098","download_url":"https://codeload.github.com/hoc081098/dart_either/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoc081098%2Fdart_either/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30214578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T12:15:00.571Z","status":"ssl_error","status_checked_at":"2026-03-07T12:15:00.217Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","dart-either","dart-either-monad","dart-functional","dart-functional-programming","either","either-dart","either-monad","flutter-functional","functional","functional-programming","pub"],"created_at":"2024-10-15T05:45:26.484Z","updated_at":"2026-03-07T13:01:04.232Z","avatar_url":"https://github.com/hoc081098.png","language":"Dart","funding_links":["https://www.buymeacoffee.com/hoc081098"],"categories":[],"sub_categories":[],"readme":"# dart_either\n\n\u003e **Author:** [Petrus Nguyễn Thái Học](https://github.com/hoc081098)\n\n[![Dart CI](https://github.com/hoc081098/dart_either/workflows/Dart%20CI/badge.svg)](https://github.com/hoc081098/dart_either/actions)\n[![pub version](https://img.shields.io/pub/v/dart_either)](https://pub.dev/packages/dart_either)\n[![pub prerelease](https://img.shields.io/pub/v/dart_either?include_prereleases)](https://pub.dev/packages/dart_either)\n[![codecov](https://codecov.io/gh/hoc081098/dart_either/branch/master/graph/badge.svg)](https://codecov.io/gh/hoc081098/dart_either)\n[![License: MIT](https://img.shields.io/github/license/hoc081098/dart_either?color=4EB1BA)](https://opensource.org/licenses/MIT)\n[![Style: lints](https://img.shields.io/badge/style-lints-40c4ff.svg)](https://pub.dev/packages/lints)\n[![Hits](https://hits.sh/github.com/hoc081098/dart_either.svg)](https://hits.sh/github.com/hoc081098/dart_either/)\n\n**Either monad for Dart \u0026 Flutter** — a type-safe, lightweight library for error handling and railway-oriented programming.\n\n- ✅ **Monad comprehensions** — both `sync` (`Either.binding`) and `async` (`Either.futureBinding`) versions.\n- ✅ **Async `map` / `flatMap`** — hides the boilerplate of working with `Future\u003cEither\u003cL, R\u003e\u003e`.\n- ✅ **Type-safe** — an explicit, compiler-friendly alternative to nullable values and thrown exceptions.\n\n\u003e **Credits:** Ported and adapted from [Λrrow-kt](https://github.com/arrow-kt/arrow).\n\n---\n\n## Support the project\n\nIf you find this library useful, consider buying me a coffee ☕\n\n\u003ca href=\"https://www.buymeacoffee.com/hoc081098\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\n  \u003cimg src=\"https://cdn.buymeacoffee.com/buttons/v2/default-blue.png\" alt=\"Buy Me A Coffee\" height=\"64\"\u003e\n\u003c/a\u003e\n\n---\n\n## Why `dart_either`?\n\n### Difference from [dartz](https://pub.dev/packages/dartz) and [fpdart](https://pub.dev/packages/fpdart)\n\nMany projects import entire FP libraries (dartz, fpdart, …) but only use `Either`. This library extracts and adapts just the `Either` class from [Λrrow-kt](https://github.com/arrow-kt/arrow), keeping things focused and lightweight.\n\n| Feature              | dart_either                                                                                                                   |\n|----------------------|-------------------------------------------------------------------------------------------------------------------------------|\n| Inspired by          | [Λrrow-kt](https://github.com/arrow-kt/arrow), [Scala Cats](https://typelevel.org/cats/typeclasses.html#type-classes-in-cats) |\n| Documentation        | **Fully documented** — every method/function has doc comments and examples                                                    |\n| Test coverage        | **Fully tested**                                                                                                              |\n| Completeness         | **Most complete** `Either` implementation available for Dart/Flutter                                                          |\n| Monad comprehensions | ✅ Both `sync` and `async`                                                                                                     |\n| Async map / flatMap  | ✅ `thenMapEither`, `thenFlatMapEither`                                                                                        |\n| Bundle size          | Very **lightweight** and **simple** (compare to dartz)                                                                        |\n\n---\n\n## Getting started\n\nAdd the dependency to your `pubspec.yaml`:\n\n```yaml\ndependencies:\n  dart_either: ^2.1.0\n```\n\nThen run:\n\n```bash\ndart pub get\n```\n\n---\n\n## Documentation \u0026 Examples\n\n| Resource             | Link                                                                                  |\n|----------------------|---------------------------------------------------------------------------------------|\n| 📖 API Documentation | https://pub.dev/documentation/dart_either/latest/dart_either/ |\n| 💡 Examples          | https://github.com/hoc081098/dart_either/tree/master/example/lib                      |\n| 🐦 Flutter Example   | https://github.com/hoc081098/node-auth-flutter-BLoC-pattern-RxDart                    |\n\n---\n\n## Either monad\n\n`Either\u003cL, R\u003e` represents one of two possible values:\n\n- **`Right(R)`** — the \"desired\" / success value (right-biased).\n- **`Left(L)`** — the \"undesired\" / error value.\n\nRelated implementations in other languages:\n- [Elm Result](https://package.elm-lang.org/packages/elm-lang/core/5.1.1/Result)\n- [Haskell Data.Either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html)\n- [Rust Result](https://doc.rust-lang.org/std/result/enum.Result.html)\n\n\u003cdetails\u003e\n  \u003csummary\u003eWhy Either? (click to expand)\u003c/summary\u003e\n\nIn day-to-day programming, it is fairly common to find ourselves writing functions that can fail.\nFor instance, querying a service may result in a connection issue, or some unexpected `JSON` response.\n\nTo communicate these errors, it has become common practice to throw exceptions; however,\nexceptions are not tracked in any way, shape, or form by the compiler. To see what\nkind of exceptions (if any) a function may throw, we have to dig through the source code.\nThen, to handle these exceptions, we have to make sure we catch them at the call site. This\nall becomes even more unwieldy when we try to compose exception-throwing procedures.\n\n```dart\n// What exceptions can this throw? You have to dig through the source to find out.\ndouble throwsSomeStuff(int i) =\u003e throw UnimplementedError();\n\n// Same here — no way to know from the type signature alone.\nString throwsOtherThings(double d) =\u003e throw UnimplementedError();\n\n// And here too.\nList\u003cint\u003e moreThrowing(String s) =\u003e throw UnimplementedError();\n\n// Any of the three above can throw — good luck tracking which one failed!\nList\u003cint\u003e magic(int i) =\u003e moreThrowing( throwsOtherThings( throwsSomeStuff(i) ) );\n```\n\nAssume we happily throw exceptions in our code. Looking at the types of the functions above,\nany could throw a number of exceptions — we do not know. When we compose, exceptions from any\nof the constituent functions can be thrown. Moreover, they may throw the same kind of exception\n(e.g., `ArgumentError`) and, thus, it gets tricky tracking exactly where an exception came from.\n\n**How then do we communicate an error? By making it explicit in the data type we return.**\n\n`Either` is used to short-circuit a computation upon the first error.\nBy convention, the right side of an `Either` is used to hold successful values.\n\nBecause `Either` is right-biased, it is possible to define a `Monad` instance for it.\nSince we only ever want the computation to continue in the case of `Right` (as captured by\nthe right-bias nature), we fix the left type parameter and leave the right one free.\nSo, the `map` and `flatMap` methods are right-biased.\n\n**Example:**\n\n```dart\n/// Create an instance of [Right]\nfinal right = Either\u003cString, int\u003e.right(10); // Either.Right(10)\n\n/// Create an instance of [Left]\nfinal left = Either\u003cString, int\u003e.left('none'); // Either.Left(none)\n\n/// Map the right value to a [String]\nfinal mapRight = right.map((a) =\u003e 'String: $a'); // Either.Right(String: 10)\n\n/// Map the left value to a [int]\nfinal mapLeft = right.mapLeft((a) =\u003e a.length); // Either.Right(10)\n\n/// Return [Left] if the function throws an error, otherwise return [Right]\nfinal catchError = Either.catchError(\n  (e, s) =\u003e 'Error: $e',\n  () =\u003e int.parse('invalid'),\n);\n// Either.Left(Error: FormatException: Invalid radix-10 number (at character 1)\n// invalid\n// ^\n// )\n\n/// Extract the value from [Either]\nfinal value1 = right.getOrElse(() =\u003e -1); // 10\nfinal value2 = right.getOrHandle((l) =\u003e -1); // 10\n\n/// Chain computations\nfinal flatMap = right.flatMap((a) =\u003e Either.right(a + 10)); // Either.Right(20)\n\n/// Pattern matching\nright.fold(\n  ifLeft: (l) =\u003e print('Left value: $l'),\n  ifRight: (r) =\u003e print('Right value: $r'),\n); // Right value: 10\n\nright.when(\n  ifLeft: (l) =\u003e print('Left: $l'),\n  ifRight: (r) =\u003e print('Right: $r'),\n); // Prints Right: Either.Right(10)\n\n// Or use Dart 3.0 switch expression syntax 🤘\nprint(\n  switch (right) {\n    Left() =\u003e 'Left: $right',\n    Right() =\u003e 'Right: $right',\n  },\n); // Prints Right: Either.Right(10)\n\n/// Convert to nullable value\nfinal nullableValue = right.orNull(); // 10\n```\n\n\u003c/details\u003e\n\n---\n\n## API Reference\n\n\u003e Full API docs: https://pub.dev/documentation/dart_either/latest/dart_either/\n\n### 1. Creation\n\n#### 1.1. Factory constructors\n\n| Constructor                                                                                                       | Description                 |\n|-------------------------------------------------------------------------------------------------------------------|-----------------------------|\n| [`Either.left`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/Either.left.html)             | Creates a `Left` value      |\n| [`Either.right`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/Either.right.html)           | Creates a `Right` value     |\n| [`Either.binding`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/Either.binding.html)       | Sync monad comprehension    |\n| [`Either.catchError`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/Either.catchError.html) | Wraps a throwing expression |\n| [`Left`](https://pub.dev/documentation/dart_either/latest/dart_either/Left/Left.html)                             | Direct `Left` constructor   |\n| [`Right`](https://pub.dev/documentation/dart_either/latest/dart_either/Right/Right.html)                          | Direct `Right` constructor  |\n\n```dart\n// Left('Left value')\nfinal left = Either\u003cObject, String\u003e.left('Left value');\n// or: Left\u003cObject, String\u003e('Left value')\n\n// Right(1)\nfinal right = Either\u003cObject, int\u003e.right(1);\n// or: Right\u003cObject, int\u003e(1)\n\n// Left('Left value') — short-circuits on the first bind that returns Left\nEither\u003cObject, String\u003e.binding((e) {\n  final String s = left.bind(e);\n  final int i = right.bind(e);\n  return '$s $i';\n});\n\n// Left(FormatException(...))\nEither.catchError(\n  (e, s) =\u003e 'Error: $e',\n  () =\u003e int.parse('invalid'),\n);\n```\n\n#### 1.2. Static methods\n\n| Method                                                                                                                 | Description                              |\n|------------------------------------------------------------------------------------------------------------------------|------------------------------------------|\n| [`Either.catchFutureError`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/catchFutureError.html) | Wraps an async throwing expression       |\n| [`Either.catchStreamError`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/catchStreamError.html) | Wraps a stream that may throw            |\n| [`Either.fromNullable`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/fromNullable.html)         | Converts a nullable value                |\n| [`Either.futureBinding`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/futureBinding.html)       | Async monad comprehension                |\n| [`Either.parSequenceN`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/parSequenceN.html)         | Parallel sequence with concurrency limit |\n| [`Either.parTraverseN`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/parTraverseN.html)         | Parallel traverse with concurrency limit |\n| [`Either.sequence`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/sequence.html)                 | Sequences a list of `Either`s            |\n| [`Either.traverse`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/traverse.html)                 | Maps + sequences a list                  |\n\n```dart\nimport 'package:http/http.dart' as http;\n\n// ─── Either.catchFutureError ─────────────────────────────────────────────────\nFuture\u003cEither\u003cString, http.Response\u003e\u003e eitherFuture = Either.catchFutureError(\n  (e, s) =\u003e 'Error: $e',\n  () async {\n    final uri = Uri.parse('https://pub.dev/packages/dart_either');\n    return http.get(uri);\n  },\n);\n(await eitherFuture).fold(ifLeft: print, ifRight: print);\n\n\n// ─── Either.catchStreamError ─────────────────────────────────────────────────\nStream\u003cint\u003e genStream() async* {\n  for (var i = 0; i \u003c 5; i++) {\n    yield i;\n  }\n  throw Exception('Fatal');\n}\nStream\u003cEither\u003cString, int\u003e\u003e eitherStream = Either.catchStreamError(\n  (e, s) =\u003e 'Error: $e',\n  genStream(),\n);\neitherStream.listen(print);\n\n\n// ─── Either.fromNullable ─────────────────────────────────────────────────────\nEither.fromNullable\u003cint\u003e(null); // Left(null)\nEither.fromNullable\u003cint\u003e(1);    // Right(1)\n\n\n// ─── Either.futureBinding ────────────────────────────────────────────────────\nString url1 = 'url1';\nString url2 = 'url2';\nEither.futureBinding\u003cString, http.Response\u003e((e) async {\n  final response = await Either.catchFutureError(\n    (e, s) =\u003e 'Get $url1: $e',\n    () async {\n      final uri = Uri.parse(url1);\n      return http.get(uri);\n    },\n  ).bind(e);\n\n  final id = Either.catchError(\n    (e, s) =\u003e 'Parse $url1 body: $e',\n    () =\u003e jsonDecode(response.body)['id'] as String,\n  ).bind(e);\n\n  return await Either.catchFutureError(\n    (e, s) =\u003e 'Get $url2: $e',\n    () async {\n      final uri = Uri.parse('$url2?id=$id');\n      return http.get(uri);\n    },\n  ).bind(e);\n});\n\n\n// ─── Either.sequence ─────────────────────────────────────────────────────────\nList\u003cEither\u003cString, http.Response\u003e\u003e eithers = await Future.wait(\n  [1, 2, 3, 4, 5].map((id) {\n    final url = 'url?id=$id';\n    return Either.catchFutureError(\n      (e, s) =\u003e 'Get $url: $e',\n      () async {\n        final uri = Uri.parse(url);\n        return http.get(uri);\n      },\n    );\n  }),\n);\nEither\u003cString, BuiltList\u003chttp.Response\u003e\u003e result = Either.sequence(eithers);\n\n\n// ─── Either.traverse ─────────────────────────────────────────────────────────\nEither\u003cString, BuiltList\u003cUri\u003e\u003e urisEither = Either.traverse(\n  ['url1', 'url2', '::invalid::'],\n  (String uriString) =\u003e Either.catchError(\n    (e, s) =\u003e 'Failed to parse $uriString: $e',\n    () =\u003e Uri.parse(uriString),\n  ),\n); // Left(FormatException('Failed to parse ::invalid:::...'))\n\n\n// ─── Either.parSequenceN ─────────────────────────────────────────────────────\nFuture\u003cEither\u003cString, BuiltList\u003cint\u003e\u003e\u003e result = Either.parSequenceN(\n  functions: [\n    () async =\u003e fetchNumber(1),\n    () async =\u003e fetchNumber(2),\n    () async =\u003e fetchNumber(3),\n  ],\n  maxConcurrent: 2,\n);\n\n// ─── Either.parTraverseN ─────────────────────────────────────────────────────\nFuture\u003cEither\u003cString, BuiltList\u003cint\u003e\u003e\u003e idsEither = Either.parTraverseN(\n  values: [1, 2, 3],\n  mapper: (id) =\u003e () async =\u003e fetchNumber(id),\n  maxConcurrent: 2,\n);\n```\n\n#### 1.3. Extension methods\n\n| Extension                                                                                                                           | Description                                    |\n|-------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------|\n| [`Stream.toEitherStream`](https://pub.dev/documentation/dart_either/latest/dart_either/ToEitherStreamExtension/toEitherStream.html) | Converts a stream, catching errors into `Left` |\n| [`Future.toEitherFuture`](https://pub.dev/documentation/dart_either/latest/dart_either/ToEitherFutureExtension/toEitherFuture.html) | Converts a future, catching errors into `Left` |\n| [`T.left`](https://pub.dev/documentation/dart_either/latest/dart_either/ToEitherObjectExtension/left.html)                          | Wraps any value as `Left`                      |\n| [`T.right`](https://pub.dev/documentation/dart_either/latest/dart_either/ToEitherObjectExtension/right.html)                        | Wraps any value as `Right`                     |\n\n```dart\n// ─── Stream.toEitherStream ───────────────────────────────────────────────────\nStream\u003cint\u003e genStream() async* {\n  for (var i = 0; i \u003c 5; i++) {\n    yield i;\n  }\n  throw Exception('Fatal');\n}\nStream\u003cEither\u003cString, int\u003e\u003e eitherStream =\n    genStream().toEitherStream((e, s) =\u003e 'Error: $e');\neitherStream.listen(print);\n\n\n// ─── Future.toEitherFuture ───────────────────────────────────────────────────\nFuture\u003cEither\u003cObject, int\u003e\u003e f1 =\n    Future\u003cint\u003e.error('An error').toEitherFuture((e, s) =\u003e e);\nFuture\u003cEither\u003cObject, int\u003e\u003e f2 =\n    Future\u003cint\u003e.value(1).toEitherFuture((e, s) =\u003e e);\nawait f1; // Left('An error')\nawait f2; // Right(1)\n\n\n// ─── T.left / T.right ────────────────────────────────────────────────────────\nEither\u003cint, String\u003e left = 1.left\u003cString\u003e();\nEither\u003cString, int\u003e right = 2.right\u003cString\u003e();\n```\n\n---\n\n### 2. Operations\n\n| Method                                                                                                                 | Description                                   |\n|------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|\n| [`isLeft`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/isLeft.html)                            | Returns `true` if this is a `Left`            |\n| [`isRight`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/isRight.html)                          | Returns `true` if this is a `Right`           |\n| [`fold`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/fold.html)                                | Applies one of two functions based on variant |\n| [`foldLeft`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/foldLeft.html)                        | Left fold with an initial value               |\n| [`swap`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/swap.html)                                | Swaps `Left` and `Right`                      |\n| [`tapLeft`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/tapLeft.html)                          | Side-effect on `Left`                         |\n| [`tap`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/tap.html)                                  | Side-effect on `Right`                        |\n| [`map`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/map.html)                                  | Transforms the `Right` value                  |\n| [`mapLeft`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/mapLeft.html)                          | Transforms the `Left` value                   |\n| [`flatMap`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/flatMap.html)                          | Chains computations                           |\n| [`bimap`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/bimap.html)                              | Transforms both sides                         |\n| [`exists`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/exists.html)                            | Tests the `Right` value with a predicate      |\n| [`all`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/all.html)                                  | Returns `true` for `Left` or if `Right` matches the predicate |\n| [`getOrElse`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/getOrElse.html)                      | Extracts `Right` or falls back to a default   |\n| [`orNull`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/orNull.html)                            | Extracts `Right` or returns `null`            |\n| [`getOrHandle`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/getOrHandle.html)                  | Extracts `Right` or maps `Left` to a value    |\n| [`findOrNull`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/findOrNull.html)                    | Finds `Right` matching a predicate            |\n| [`when`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/when.html)                                | Pattern-match returning the matched value     |\n| [`handleErrorWith`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/handleErrorWith.html)          | Recovers from `Left` with a new `Either`      |\n| [`handleError`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/handleError.html)                  | Recovers from `Left` with a new `Right` value |\n| [`redeem`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/redeem.html)                            | Maps both sides to the same type              |\n| [`redeemWith`](https://pub.dev/documentation/dart_either/latest/dart_either/Either/redeemWith.html)                    | Maps both sides to a new `Either`             |\n| [`toFuture`](https://pub.dev/documentation/dart_either/latest/dart_either/AsFutureEitherExtension/toFuture.html)       | Converts to a `Future`                        |\n| [`getOrThrow`](https://pub.dev/documentation/dart_either/latest/dart_either/GetOrThrowEitherExtension/getOrThrow.html) | Extracts `Right` or throws the `Left` value   |\n\n---\n\n### 3. Extensions on `Future\u003cEither\u003cL, R\u003e\u003e`\n\n| Method                                                                                                                                 | Description                           |\n|----------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|\n| [`thenFlatMapEither`](https://pub.dev/documentation/dart_either/latest/dart_either/AsyncFlatMapFutureExtension/thenFlatMapEither.html) | Async `flatMap` on a `Future\u003cEither\u003e` |\n| [`thenMapEither`](https://pub.dev/documentation/dart_either/latest/dart_either/AsyncMapFutureExtension/thenMapEither.html)             | Async `map` on a `Future\u003cEither\u003e`     |\n\n```dart\nFuture\u003cEither\u003cAsyncError, dynamic\u003e\u003e httpGetAsEither(String uriString) {\n  Either\u003cAsyncError, dynamic\u003e toJson(http.Response response) =\u003e\n      response.statusCode \u003e= 200 \u0026\u0026 response.statusCode \u003c 300\n          ? Either\u003cAsyncError, dynamic\u003e.catchError(\n              toAsyncError,\n              () =\u003e jsonDecode(response.body),\n            )\n          : AsyncError(\n              HttpException(\n                'statusCode=${response.statusCode}, body=${response.body}',\n                uri: response.request?.url,\n              ),\n              StackTrace.current,\n            ).left\u003cdynamic\u003e();\n\n  Future\u003cEither\u003cAsyncError, http.Response\u003e\u003e httpGet(Uri uri) =\u003e\n      Either.catchFutureError(toAsyncError, () =\u003e http.get(uri));\n\n  final uri =\n      Future.value(Either.catchError(toAsyncError, () =\u003e Uri.parse(uriString)));\n\n  return uri.thenFlatMapEither(httpGet).thenFlatMapEither\u003cdynamic\u003e(toJson);\n}\n\nEither\u003cAsyncError, BuiltList\u003cUser\u003e\u003e toUsers(List list) { ... }\n\nEither\u003cAsyncError, BuiltList\u003cUser\u003e\u003e result = await httpGetAsEither(\n        'https://jsonplaceholder.typicode.com/users')\n    .thenMapEither((dynamic json) =\u003e json as List)\n    .thenFlatMapEither(toUsers);\n```\n\n---\n\n### 4. Monad comprehensions\n\nUse `Either.binding` (sync) or `Either.futureBinding` (async) for do-notation style sequential\ncomputations that short-circuit on the first `Left`.\n\n```dart\nFuture\u003cEither\u003cAsyncError, dynamic\u003e\u003e httpGetAsEither(String uriString) =\u003e\n    Either.futureBinding\u003cAsyncError, dynamic\u003e((e) async {\n      final uri =\n          Either.catchError(toAsyncError, () =\u003e Uri.parse(uriString)).bind(e);\n\n      final response = await Either.catchFutureError(\n        toAsyncError,\n        () =\u003e http.get(uri),\n      ).bind(e);\n\n      e.ensure(\n        response.statusCode \u003e= 200 \u0026\u0026 response.statusCode \u003c 300,\n        () =\u003e AsyncError(\n          HttpException(\n            'statusCode=${response.statusCode}, body=${response.body}',\n            uri: response.request?.url,\n          ),\n          StackTrace.current,\n        ),\n      );\n\n      return Either\u003cAsyncError, dynamic\u003e.catchError(\n        toAsyncError,\n        () =\u003e jsonDecode(response.body),\n      ).bind(e);\n    });\n\nEither\u003cAsyncError, BuiltList\u003cUser\u003e\u003e toUsers(List list) { ... }\n\nEither\u003cAsyncError, BuiltList\u003cUser\u003e\u003e result = await Either.futureBinding((e) async {\n  final dynamic json =\n      await httpGetAsEither('https://jsonplaceholder.typicode.com/users').bind(e);\n  final BuiltList\u003cUser\u003e users = toUsers(json as List).bind(e);\n  return users;\n});\n```\n\n---\n\n## References\n\n- [Functional Error Handling — Arrow-kt](https://arrow-kt.io/docs/patterns/error_handling/)\n- [Monad — Arrow-kt](https://arrow-kt.io/docs/patterns/monads/)\n- [Monad Comprehensions — Arrow-kt](https://arrow-kt.io/docs/patterns/monad_comprehensions/)\n\n---\n\n## Features and bugs\n\nPlease file feature requests and bugs at the [issue tracker](https://github.com/hoc081098/dart_either/issues).\n\n---\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2021-2026 Petrus Nguyễn Thái Học\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoc081098%2Fdart_either","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhoc081098%2Fdart_either","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoc081098%2Fdart_either/lists"}