パッケージ、リポジトリ、アプリカテゴリを検索

パッケージ詳細v5.3.0

multiple_result

dart の複数の結果。dartz の Either や Kotlin のシールドクラスにインスパイアされています

AndroidiOSWebmacOSWindowsLinux
30日間ダウンロード
4.5万
いいね数
174
Pub ポイント
160

パッケージをインストール

flutter pub add multiple_result

パッケージ概要

公開情報に基づく選定ガイドです。参考としてご利用ください。

Multiple_result は、dartz の Either や Kotlin の sealed クラスにインスパイアされた、型安全な方法で複数の可能性のある結果を処理するための堅牢な Dart パッケージです。開発者が複数の成功または失敗状態を持つ複雑な結果型をモデル化できるようにし、コードの明確さとエラー処理を向上させます。このパッケージは網羅的なパターンマッチングをサポートしており、すべての主要プラットフォームで使用することを想定しており、Flutter および他の Dart アプリケーションにおける関数型プログラミングに最適です。

用途

  • APIにおける複数の成功またはエラー状態の処理
  • 明確な結果タイプを使用した状態管理の実装
  • 明確な結果を活用したレジリエントなビジネスロジックの構築
  • Dartにおける関数型プログラミングパターンのサポート
  • さまざまな結果を持つ非同期操作の管理

主な機能

  • 複数の結果タイプをサポートしています
  • 包括的なパターンマッチング
  • 型安全な結果処理
  • Kotlin の sealed class と dartz Either にインスパイアされて
  • クロスプラットフォーム互換性

適している対象

  • Dartで関数型プログラミングを使用する開発者
  • タイプの安全性とエラー処理を重視するチーム
  • 構造化された結果管理を必要とするFlutterアプリ
  • 複雑な状態遷移を持つプロジェクト

注意事項

  • 関数型のコンセプトを理解する必要があります
  • 簡単なケースではボイラープレートが増える可能性があります
  • 複雑なワークフローを持つ大規模なアプリケーションに最適
  • 複数のバリアントがない基本的な成功/失敗シナリオには適していない

元の README

関連するソースリポジトリの README 原文のスナップショットです。最新の内容はリポジトリをご覧ください。

multiple_result

A Result package for Dart inspired by dartz's Either type and Kotlin's sealed classes.

This package is perfect for those who just want the multiple results functionality from dartz. 👌

Using the Result type:

In your function signature, declare it to return a Result type:

Result getSomething();

Then specify the Success and Error types:

Result<String, Exception> getSomething() {

}

When returning from the function, simply use:

return Success('Success!');

or

return Error(Exception('Some error happened...'));

A complete function looks like this:

Future<Result<String, Exception>> getSomething() async {
    
    try {
      final response = await _api.get('/foo');
      final data = response.data['bar'];
      return Success(data);
    } catch(e) {
      return Error(e);
    }
}
Handling Results
Using switch:
void main() {
  final result = getSomething();
  switch(result) {
    case Success():
      print("${result.success}");
      break;
    case Error():
      print("${result.error}");
      break;
  }
}

Or with Switch Expression:

  final result = await getSomething();
  final output = switch (result) {
    Success(success: var s) => processSuccess(s),
    Error(error: var e) => handleError(e)
  };
Using when:
void main() {
    final result = await getSomething();
    final String message = result.when(
        (data) {
          // handle the success here
          return "Successfully fetched data: $data";
        },
        (error) {
          // handle the error here
          return "error: $error";
        },
    );
}
Using if case:
void main() {
  final result = getSomething();
  if(result case Success()) {
    // access to .success value
    print("${result.success}");
  }
}
Using whenSuccess or whenError
    final result = getSomethingPretty();
    // Note that [whenSuccess] or [whenError] will only be executed if
    // the result is a Success or an Error respectively. 
    final output = result.whenSuccess((name) {
        // handle here the success
        return "";
    });
    
    final result = getSomethingPretty();
    
    // If [result] is NOT an Error, this [output] will be null.
    final output = result.whenError((exception) {
        // handle here the error
        return "";
    });
Using getOrThrow

You can use getOrThrow to get the value when you're sure that the result is a Success. Be aware that calling this method when the result is actually an Error will throw a SuccessResultNotFoundException.

    final result = await getSomething();

    if (result.isSuccess()) {
      // Here, you can "safely" get the success result as it was verified in the previous line.
      final mySuccessResult = result.getOrThrow();
    }
Using tryGetSuccess
void main() {
    final result = getSomethingPretty();

    String? mySuccessResult;
    if (result.isSuccess()) {
      mySuccessResult = result.tryGetSuccess();
    }
}
Using tryGetError
void main() {
    final result = getSomethingPretty();

    Exception? myException;
    if (result.isError()) {
      myException = result.tryGetError();
    }
}

Using getBoth

The getBoth method returns a record (Dart's named tuple) containing both the success and error values of a Result. Only one of these will be non-null, depending on whether the result is a Success or an Error.

  • If the result is a Success, the success field will contain the value, and error will be null.
  • If the result is an Error, the error field will contain the error, and success will be null.

This is useful for destructuring or pattern matching without having to check the type explicitly.

Example:

void main() {
  final result = getSomething();
  final (:success, :error) = result.getBoth();
  
  if (success != null) {
    print("Success: $success");
  } else {
    print("Error: $error");
  }
}

Transforming Results

The Result class provides several methods for transforming values while preserving the success/error structure:

Using map

The map method transforms both the success and error values of a Result:

Result<int, Exception> result = fetchNumber();
Result<String, String> transformed = result.map(
  successMapper: (number) => number.toString(),
  errorMapper: (exception) => exception.toString()
);
Using mapSuccess

The mapSuccess method transforms only the success value, preserving any error:

Result<int, Exception> result = fetchNumber();
Result<String, Exception> transformed = result.mapSuccess(
  (number) => number.toString()
);
Using mapError

The mapError method transforms only the error value, preserving any success:

Result<int, Exception> result = fetchNumber();
Result<int, String> transformed = result.mapError(
  (exception) => exception.toString()
);
Using flatMap

The flatMap method is powerful for chaining operations that can fail. Unlike mapSuccess which wraps the returned value in a Result, flatMap expects your function to return a Result directly:

Result<int, String> fetchNumber() => Success(5);

Result<String, String> parseNumber(int n) {
  if (n > 0) {
    return Success(n.toString());
  } else {
    return Error("Cannot parse negative numbers");
  }
}

// Chain operations that might fail
Result<String, String> result = fetchNumber().flatMap(
  (number) => parseNumber(number)
);

The key difference between mapSuccess and flatMap:

  • mapSuccess takes a function that returns a value T and wraps it in a Result
  • flatMap takes a function that returns a Result directly, avoiding nested Results
Using Result.tryCatch

Replace try/catch blocks with Result.tryCatch to convert a throwing operation directly into a Result:

final result = Result.tryCatch(
  () => int.parse(userInput),
  (error, stackTrace) => ParseError(error.toString()),
);
// result is Success(42) or Error(ParseError(...))
Using getOrElse

Provide a fallback value computed from the error instead of throwing:

final value = result.getOrElse((error) => defaultValue);
Using onSuccess / onError

Run side effects (e.g. logging) in the middle of a chain without breaking it:

result
    .onSuccess((data) => logger.info('Got $data'))
    .onError((error) => logger.error('Failed: $error'))
    .mapSuccess((data) => data.toUpperCase());
Using flatMapError / recover

Handle errors and recover into a new Result, symmetric to flatMap:

final result = fetchUser(id)
    .flatMapError((e) => fetchUserFromCache(id));

// or with the alias:
final result = fetchUser(id)
    .recover((e) => fetchUserFromCache(id));
Using swap

Convert a Success into an Error and vice versa — useful for inverting validation logic:

final inverted = result.swap();
// Success('x') becomes Error('x'), Error(e) becomes Success(e)

Async Results with AsyncResult

AsyncResult<S, E> is a zero-cost wrapper around Future<Result<S, E>> using Dart extension types. It lets you chain transformations on async results fluently without awaiting at each step.

// Wrap a Future<Result> as AsyncResult
AsyncResult<User, ApiError> fetchUser(int id) =>
    AsyncResult(api.get('/users/$id').then((r) => r.toResult()));

// Chain operations without intermediate awaits
final greeting = await fetchUser(42)
    .mapSuccess((user) => user.name.toUpperCase())
    .onError((e) => logger.error('Failed: $e'))
    .getOrElse((_) => 'Anonymous');

Use AsyncResult.tryCatch to wrap a potentially-throwing async function:

final result = AsyncResult.tryCatch(
  () async => await api.fetchUser(id),
  (error, stack) => NetworkError(error.toString()),
);

Use flatMapAsync to chain operations that are themselves async:

final result = fetchUser(42)
    .flatMapAsync((user) => fetchPosts(user.id));

Unit Type

Some results don't need a specific return value. Use the Unit type to signal an empty return:

    Result<Unit, Exception>

ResultOf

You may have noticed the ResultOf typedef. It represents a more readable alternative for Result.

カテゴリー

ソースリポジトリ

このパッケージを使用しているプロジェクト