brianegan / dart_redux_epics

Redux.dart middleware for handling actions using Dart Streams
MIT License
141 stars 22 forks source link

Unhandled Exception: type 'LoadAccountErrorAction' is not a subtype of type 'FutureOr<LoadAccountCompleteAction>' #30

Closed lionlin closed 5 years ago

lionlin commented 5 years ago

I'm using dart_redux_epics, but catcherror can not return error actions Epics:

Stream<dynamic> loadAccountEpic(Stream<dynamic> actions, EpicStore<AppState> store) {
return new Observable(actions).
ofType(new TypeToken<LoadAccountAction>())
.flatMap((action) {
    return new Observable.fromFuture(NetUtils.getInstance()
        .userInfo(pb.UserInfoRequest())
        .then((res) => LoadAccountCompleteAction(res.user))
        .catchError((error) => LoadAccountErrorAction(error)));
  });

Actions:

class LoadAccountAction {
  LoadAccountAction();
}

class LoadAccountCompleteAction {
  User user;

  LoadAccountCompleteAction(this.user);

  @override
  String toString() {
    return 'LoadAccountCompleteAction{user: $user}';
  }
}

class LoadAccountErrorAction {
  final dynamic error;

  LoadAccountErrorAction(this.error);

  @override
  String toString() {
    return 'LoadAccountErrorAction{error: $error}';
  }
}

Errors:

[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: type 'LoadAccountErrorAction' is not a subtype of type 'FutureOr<LoadAccountCompleteAction>'
brianegan commented 5 years ago

Ack, sorry I missed this one! This looks like a type error -- Dart is inferring from the Future that the Observable is actually an Observable<LoadAccountCompleteAction> instead of the more generic LoadAccountAction. Therefore, when you try to emit the LoadAccountErrorAction, you see such a Type error.

To fix this, change the definition of the observable to specify the abstract type:

    return new Observable<LoadAccountAction>.fromFuture(NetUtils.getInstance()...
talamaska commented 4 years ago

@brianegan How to resolve this issue if I'm not using observables here

Epic<AppState> addFeed(
    FeedRepository feedRepo, FeedsDatabaseRepository feedsRepo) {
  return (Stream<dynamic> actions, EpicStore<AppState> store) {
    return Observable<dynamic>(actions)
        .ofType<AddFeedAction>(const TypeToken<AddFeedAction>())
        .asyncMap<dynamic>((action) {
      return feedRepo
          .getFeed(action.payload.url)
          .then((result) => feedsRepo.insert(result))
          .then((FeedModel _inserted) {
        debugPrint('inserted $_inserted');
        return AddFeedDoneAction(_inserted);
      }).catchError((dynamic error) {
        debugPrint('error $error');
        return AddFeedErrorAction(error);
      }).catchError((dynamic error) => AddFeedErrorAction(error));
    });
  };
}

I got the same exception Unhandled Exception: type 'AddFeedErrorAction' is not a subtype of type 'FutureOr' and my actions

class AddFeedAction {
  final FeedModel payload;

  AddFeedAction(this.payload);

  @override
  String toString() {
    return 'GetFeedAction{payload: $payload}';
  }
}

class AddFeedDoneAction {
  final FeedModel payload;

  AddFeedDoneAction(this.payload);

  @override
  String toString() {
    return 'AddFeedDoneAction{payload: $payload}';
  }
}
class AddFeedErrorAction {
  final dynamic payload;

  AddFeedErrorAction(this.payload);

  @override
  String toString() {
    return 'AddFeedErrorAction{payload: $payload}';
  }
}

even this one is breaking with the same error

Epic<AppState> addFeed(
    FeedRepository feedRepo, FeedsDatabaseRepository feedsRepo) {
  return (Stream<dynamic> actions, EpicStore<AppState> store) {
    return actions
        .where((dynamic action) => action is AddFeedAction)
        .asyncMap<dynamic>((dynamic action) =>
            // Pseudo api that returns a Future of SearchResults
            feedRepo
                .getFeed(action.payload.url)
                .then((results) => feedsRepo.insert(results))
                .then((FeedModel _inserted) => AddFeedDoneAction(_inserted))
                .catchError((dynamic error) => AddFeedErrorAction(error)));
  };
}