{"id":13549632,"url":"https://github.com/avdosev/either_dart","last_synced_at":"2025-10-23T08:17:50.093Z","repository":{"id":50610158,"uuid":"294974772","full_name":"avdosev/either_dart","owner":"avdosev","description":"Either class for Dart or Flutter projects.","archived":false,"fork":false,"pushed_at":"2023-06-10T18:37:27.000Z","size":100,"stargazers_count":26,"open_issues_count":1,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-08-01T12:19:04.475Z","etag":null,"topics":["dart","dart-either","dart-either-monad","dart-functional-programming","either","either-dart","error-handling","flutter","functional-programming"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/either_dart","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/avdosev.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":null,"dei":null}},"created_at":"2020-09-12T15:47:48.000Z","updated_at":"2024-05-31T05:47:58.000Z","dependencies_parsed_at":"2024-03-16T22:00:22.216Z","dependency_job_id":"176ceee8-fc5a-4f19-bec4-71aea5793968","html_url":"https://github.com/avdosev/either_dart","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avdosev%2Feither_dart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avdosev%2Feither_dart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avdosev%2Feither_dart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avdosev%2Feither_dart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/avdosev","download_url":"https://codeload.github.com/avdosev/either_dart/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222892557,"owners_count":17053926,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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-programming","either","either-dart","error-handling","flutter","functional-programming"],"created_at":"2024-08-01T12:01:23.833Z","updated_at":"2025-10-23T08:17:49.987Z","avatar_url":"https://github.com/avdosev.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"# either dart \u0026middot; ![build status](https://github.com/avdosev/either_dart/workflows/unittests/badge.svg)\n\n\nThe library for error handling and railway oriented programming.\n\nThis library supports async \"map\" and async \"then\" hiding the boilerplate of working with asynchronous computations Future\\[Either\\].\n\n## Installation\n\nAdd to pubspec.yml:\n\n```\ndependencies:\n  either_dart: ... // latest package version\n```\n\n## Documentation\n\nhttps://pub.dev/documentation/either_dart/latest/either/either-library.html\n\n## Pub dev\n\nhttps://pub.dev/packages/either_dart\n\n## How to use it?\n\nSections:\n* [Basic usage](#basic-usage)\n* [Advanced usage](#advanced-usage)\n* [Case - Solution](#case---solution)\n\n### Basic usage\n\nCreate two entities for example, you can use your own abstractions for your project.\n\n```dart\nenum AppError {\n  NotFound,\n  // some errors codes\n}\n\nclass MyError {\n  final AppError key;\n  final String? message;\n\n  const MyError({\n    required this.key, \n    this.message,\n  });\n}\n```\n\nWe can use Either as shown below:\n\n```dart\nEither\u003cMyError, String\u003e getCityNameByCode(int code) {\n  const cities = \u003cint, String\u003e{\n    /// some cities\n  };\n\n  if (cities.contains(code)) {\n    return Right(cities[code]!);\n  } else {\n    return Left(\n      key: AppError.NotFound, \n      message: '[getCityNameByCode] can`t convert code:$code to city name',\n    );\n  }\n}\n```\n\nToo, you can use `Either.cond` and `Either.condLazy` for simple cases:\n\n```dart\n  return Either.condLazy(cities.contains(code), \n    () =\u003e cities[code]!, \n    () =\u003e MyError(\n      key: AppError.NotFound, \n      message: '[getCityNameByCode] can`t convert code:$code to city name',\n    ),\n  );\n```\n\nEither has the following methods:\n\n***note:*** \\\nL - current `Left` type \\\nTL - new generic `Left` type \\\nR - current `Right` type \\\nTR - new generic `Right` type\n\n\n| name | result | description |\n| --- | --- | --- |\n| `isLeft` | `bool` | Represents the left side of Either class which by convention is a \"Failure\". |\n| `isRight` | `bool` | Represents the right side of Either class which by convention is a \"Success\" |\n| `left` | `L` | Get Left value, may throw an exception when the value is Right. **read-only** |\n| `right` | `R` | Get Right value, may throw an exception when the value is Left. **read-only** |\n| `either\u003cTL, TR\u003e(TL fnL(L left), TR fnR(R right))` | `Either\u003cTL, TR\u003e` | Transform values of Left and Right, equal of `bimap` in fp-libraries\n| `fold\u003cT\u003e(T fnL(L left), T fnR(R right))` | `T` | Fold Left and Right into the value of one type\n| `map\u003cTR\u003e(TR fnR(R right))` | `Either\u003cL, TR\u003e` | Transform value of Right\n| `mapLeft\u003cTL\u003e(TL fnL(L left))` | `Either\u003cTL, R\u003e` | Transform value of Left\n| `mapAsync\u003cTR\u003e(FutureOr\u003cTR\u003e fnR(R right))` | `Future\u003cEither\u003cL, TR\u003e\u003e` | Transform value of Right\n| `mapLeftAsync\u003cTL\u003e(FutureOr\u003cTL\u003e fnL(L left))` | `Future\u003cEither\u003cTL, R\u003e\u003e` | Transform value of Left\n| `swap()` | `Either\u003cR, L\u003e` | Swap Left and Right\n| `then\u003cTR\u003e(Either\u003cL, TR\u003e fnR(R right))` | `Either\u003cL, TR\u003e` | Transform value of Right when transformation may be finished with an error\n| `thenLeft\u003cTL\u003e(Either\u003cTL, R\u003e fnL(L left))` | `Either\u003cTL, R\u003e` | Transform value of Left when transformation may be finished with an Right\n| `thenAsync\u003cTR\u003e(FutureOr\u003cEither\u003cL, TR\u003e\u003e fnR(R right))` | `Future\u003cEither\u003cL, TR\u003e\u003e` | Transform value of Right when transformation may be finished with an error\n| `thenLeftAsync\u003cTL\u003e(FutureOr\u003cEither\u003cTL, R\u003e\u003e fnL(L left))` | `Future\u003cEither\u003cTL, R\u003e\u003e` | Transform value of Left when transformation may be finished with an Right\n\n### Advanced usage\n\nThis library provides an `FutureEither` extension which is designed to handle asynchronous computation with ease.\n\nYou don't need to import or use new classes to use it - just use `Future\u003cEither\u003cL, R\u003e\u003e`\n\n| name | result | description |\n| --- | --- | --- |\n`either\u003cTL, TR\u003e(TL fnL(L left), TR fnR(R right))` | `Future\u003cEither\u003cTL, TR\u003e\u003e` | Transform values of Left and Right\n`fold\u003cT\u003e(T fnL(L left), T fnR(R right))` | `Future\u003cT\u003e` | Fold Left and Right into the value of one type\n`mapRight\u003cTR\u003e(FutureOr\u003cTR\u003e fnR(R right))` | `Future\u003cEither\u003cL, TR\u003e\u003e` | Transform value of Right\n`mapLeft\u003cTL\u003e(FutureOr\u003cTL\u003e fnL(L left))` | `Future\u003cEither\u003cTL, R\u003e\u003e` | Transform value of Left\n`swap()` | `Future\u003cEither\u003cR, L\u003e\u003e` | Swap Left and Right\n`thenRight\u003cTR\u003e(FutureOr\u003cEither\u003cL, TR\u003e\u003e fnR(R right))` | `Future\u003cEither\u003cL, TR\u003e\u003e` | Async transform value of Right when transformation may be finished with an error\n`thenLeft\u003cTL\u003e(FutureOr\u003cEither\u003cTL, R\u003e\u003e fnL(L left))` | `Future\u003cEither\u003cTL, R\u003e\u003e` | Async transform value of Left when transformation may be finished with an Right\n\nExample:\n\n```dart\n/// --- helpers ---\n\nimport 'package:either_dart/either.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter/foundation.dart';\nimport 'dart:convert';\n\nFuture\u003cEither\u003cAppError, http.Response\u003e\u003e safe(Future\u003chttp.Response\u003e request) async {\n  try {\n    return Right(await request);\n  } catch (e) {\n    return Left(MyError(\n        key: AppError.BadRequest,\n        message: \"Request executing with errors:$e\"));\n  }\n}\n\nEither\u003cAppError, http.Response\u003e checkHttpStatus(http.Response response) {\n  if (response.statusCode == 200)\n    return Right(response);\n  if (response.statusCode \u003e= 500)\n    return Left(MyError(\n        key: AppError.ServerError,\n        message: \"Server error with http status ${response.statusCode}\"));\n  return Left(MyError(\n      key: AppError.BadResponse,\n      message: \"Bad http status ${response.statusCode}\"));\n}\n\nFuture\u003cEither\u003cAppError, dynamic\u003e\u003e parseJson(http.Response response) async {\n  try {\n    \n    return Right(await compute((body) {\n      final json = JsonCodec();\n      return json.decode(body)); \n    }, response.body);\n  } catch (e) {\n    return Left(MyError(\n      key: AppError.JsonParsing, \n      message: 'failed on json parsing'));\n  }\n}\n\n/// --- app code ---\n\n//// network\nFuture\u003cEither\u003cAppError, Data\u003e\u003e getDataFromServer() {\n  return \n    safe(http.get(Uri('some uri')))\n      .thenRight(checkHttpStatus)\n      .thenRight(parseJson) \n      .mapRight(Data.fromJson)\n}\n\n```\n\n### Case - Solution\n\n* How I can use the value of `Either`?\n\nYou can use right or left getters, but you should check what value is stored inside (`isLeft` or `isRight`)\n\nAlso, my favorite methods `fold`, `either`\n\n* `fold` - used when you need to transform two rails to one type\n* `either` - used for two situations: 1. when you need transform left and right. 2. when you need to use stored value without next usage (see example). \n\nExample: \n```dart\n/// either method\nshowNotification(Either\u003cMyError, String\u003e value) {\n  return value.either(\n    (left) =\u003e showWarning(left.message ?? left.key.toString()),\n    (right) =\u003e showInfo(right.toString()),\n  );\n  /// equal\n  if (value.isLeft) {\n    final left = value.left;\n    showWarning(left.message ?? left.key.toString()\n  } else {\n    showInfo(value.right.toString())\n  }\n}\n```\n```dart\n/// fold method\nclass MyWidget {\n  final Either\u003cMyError, List\u003cString\u003e\u003e value;\n\n  const MyWidget(this.value);\n\n  Widget build(BuildContext context) {\n    return Text(\n      value.fold(\n        (left) =\u003e left.message, \n        (right) =\u003e right.join(', ')),\n    );\n    /// or\n    return value.fold(\n      (left) =\u003e _buildSomeErrorWidget(context, left),\n      (right) =\u003e _buildSomeRightWidget(context, right),\n    );\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favdosev%2Feither_dart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Favdosev%2Feither_dart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favdosev%2Feither_dart/lists"}