ReactiveX / rxdart

The Reactive Extensions for Dart
http://reactivex.io
Apache License 2.0
3.35k stars 272 forks source link

WhereTypeStreamTransformer is not a subtype of type StreamTransformer #391

Open howardwkim opened 4 years ago

howardwkim commented 4 years ago

Seeing the following exception after upgrading to rxdart 0.23.1 (and after running rxdart_codemod):

Unhandled Exception: type 'WhereTypeStreamTransformer<dynamic, OnRequestMemoryLimit>' is not a subtype of type 'StreamTransformer<OnRequestMemoryLimit, OnRequestMemoryLimit>' of 'streamTransformer'

From the following code:

Stream<dynamic> getMemoryLimit(
    Stream<dynamic> actions, EpicStore<AppState> store) {
  return actions
      .whereType<OnRequestMemoryLimit>()
      .switchMap((OnRequestMemoryLimit requestAction) {
   return ...
}

I ended up switching the code (appreciate the example in the documentation!) and the exception disappears:

  return actions
      // .whereType<OnRequestMemoryLimit>()
      .where((event) => event is OnRequestMemoryLimit)
      .cast<OnRequestMemoryLimit>()
      .switchMap((OnRequestMemoryLimit requestAction)

If I want to continue using whereType, what do I need to change in my code? Or is this a bug? Thanks!

flutter doctor -v:

[✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.2 19C57, locale
    en-US)
    • Flutter version 1.12.13+hotfix.5 at /Users/howardwkim/development/flutter
    • Framework revision 27321ebbad (4 weeks ago), 2019-12-10 18:15:01 -0800
    • Engine revision 2994f7e1e6
    • Dart version 2.7.0
brianegan commented 4 years ago

Good catch, thanks! @frankpepermans Should we just change the implementation to use the default transformers anyhow and remove the custom transformer?

frankpepermans commented 4 years ago

@brianegan I can't reproduce this issue though?

Do you want to internally use where and cast like in the example?

MichaelMarner commented 3 years ago

Hey

We ran into this today after we finally got around to updating our redux epics to the latest RxDart. What I have found is that tests that used to work are now failing, but the epics themselves work fine at runtime. This seems to be due to Dart's type inference.

For example, here's an example epic:

class ExampleRequest{}
class ExampleResponse {}

class ExampleEpic extends EpicClass {
  Stream call(Stream<dynamic> actions, EpicStore<AppState> store) {
    return actions
        .whereType<ExampleRequest>()
        .switchMap<dynamic>((action) {
          // imagine an API request here
          return Stream.fromFuture(Future.delayed(Duration(seconds: 1)));
        })
        .map((response) => ExampleResponse());
  }

A unit test for this may look something like this:


void main() {
  test('Example Epic') {
    final epic = ExampleEpic();

    await expectLater(
      epics.call(
          Stream.fromIterable([ExampleRequest(), ExampleRequest()])
              .asBroadcastStream(),
          store),
      emitsInAnyOrder([
        isA<ExampleResponse>(),
        isA<ExampleResponse>(),
      ]),
    );
  }
}

This test will fail, because the Stream provided by Stream.fromIterable won't be a Stream<dynamic>, but a Stream<ExampleRequest>. Dart's type inference is being too clever for the test.

The fix here is to explicitly give the Stream a type:


    await expectLater(
      epics.call(
          Stream<dynamic>.fromIterable([ExampleRequest(), ExampleRequest()])
              .asBroadcastStream(),
          store),
      emitsInAnyOrder([
        isA<ExampleResponse>(),
        isA<ExampleResponse>(),
      ]),
    );

The test will then pass. So technically, in our case at least, the issue is with the test, not the whereType.

Having said all that, this is a regression from rxdart 0.22. It would be great if we didn't have to modify all our tests and the code worked as it did previously.