brianegan / redux_logging

Redux.dart Middleware that prints the latest action & state
MIT License
31 stars 9 forks source link

type 'List<Object>' is not a subtype of type 'List<(Store<AppState>, dynamic, (dynamic) => void) => void>' #7

Closed jaggerwang closed 6 years ago

jaggerwang commented 6 years ago

Error

Launching lib/main.dart on iPhone X in debug mode...
[VERBOSE-2:dart_error.cc(16)] Unhandled exception:
type 'List<Object>' is not a subtype of type 'List<(Store<AppState>, dynamic, (dynamic) => void) => void>'
#0      new TangboleApp (file:///Users/jagger/projects/tangbole/app/lib/main.dart:36:79)
#1      main (file:///Users/jagger/projects/tangbole/app/lib/main.dart:18:10)
#2      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:279:19)
#3      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:165:12)

Code

...

    final persistor = Persistor<AppState>(
      storage: FlutterStorage('tangbole'),
      decoder: AppState.fromJson,
      version: 10000,
      migrations: {},
    );

    var mws = [persistor.createMiddleware()];
    mws.addAll(createMiddlewares());
    mws.add(LoggingMiddleware.printer());

    final store = Store<AppState>(
      appReducer,
      initialState: AppState(),
      middleware: mws,
    );

    persistor.load(store);

...

Env

name: tangbole
description: A tumblr client app.

dependencies:
  cupertino_icons: ^0.1.2
  english_words: ^3.1.0
  flutter:
    sdk: flutter
  flutter_redux: ^0.5.1
  http: ^0.11.3+16
  meta: ^1.1.5
  redux: ^3.0.0
  redux_logging: ^0.3.0
  redux_persist: ^0.7.0-rc.2
  redux_persist_flutter: ^0.6.0-rc.1

dev_dependencies:
  flutter_driver:
    sdk: flutter
  flutter_test:
    sdk: flutter
  mockito: ^2.2.3

flutter:
  uses-material-design: true
  assets:
    - images/lake.jpg
brianegan commented 6 years ago

Hey there! Thanks for writing in... I think the problem is that you're not giving Dart2 enough type information to correctly infer what's contained in the mws list.

Could you please change var mws = [persistor.createMiddleware()]; to var mws = <Middleware<AppState>>[persistor.createMiddleware()]; and see if that fixes the issue? If that doesn't do it, could you please link to full source so I can take a closer look?

jaggerwang commented 6 years ago

Both this:

    List<Middleware<AppState>> mws = [persistor.createMiddleware()];
    mws.addAll(createMiddlewares());
    mws.add(LoggingMiddleware.printer());

and this:

var mws = <Middleware<AppState>>[persistor.createMiddleware()];
    mws.addAll(createMiddlewares());
    mws.add(LoggingMiddleware.printer());

is not working.

I think it is because the return type of printer() is LoggingMiddleware<State>, not (Store<AppState>, dynamic, (dynamic) → void) → void. There is a warning in VSCode.

[dart] The argument type 'List<LoggingMiddleware>' can't be assigned to the parameter type 'List<(Store<AppState>, dynamic, (dynamic) → void) → void>'.
brianegan commented 6 years ago

LoggingMiddleware<State> is a generic type... therefore you can pass through your own type info for it: LoggingMiddleware<AppState>.printer()

This is working for me:

final middleware = <Middleware<SearchState>>[
    SearchMiddleware(GithubApi()),
  ];
  middleware.add(LoggingMiddleware.printer());

But if sounds like you might need to provide the extra type info to the LoggingMiddleware constructor if that's not working on your side:

final middleware = <Middleware<SearchState>>[
    SearchMiddleware(GithubApi()),
  ];
  middleware.add(LoggingMiddleware<SearchState>.printer());

If this isn't working, could you please provide a repo or full source? It's difficult to debug type problems with code snippets since I can't see the full type info from my side. Also, which version of Flutter are you on? This is working for me on the beta channel, haven't tried master and the Dart 2 runtime is changing.

jaggerwang commented 6 years ago

Thanks! This worked for me:

    store = store ??
        Store<AppState>(
          appReducer,
          initialState: AppState(),
          middleware: [persistor.createMiddleware()] +
              createMiddlewares() +
              <Middleware<AppState>>[LoggingMiddleware.printer()],
        );

But not this:

    store = store ??
        Store<AppState>(
          appReducer,
          initialState: AppState(),
          middleware: [persistor.createMiddleware()] +
              createMiddlewares() +
              [LoggingMiddleware<AppState>.printer()],
        );

It should works too. I already specified the generic param type AppState, and printer() should return type (Store<AppState>, dynamic, (dynamic) → void) → void.

brianegan commented 6 years ago

Ah, yah, it is a bit confusing... it's really all about providing the proper type info to Dart. In the second example, Dart isn't properly inferring the List as a Middleware<AppState> and therefore you need to help it out a bit.

Glad it's working!

jaggerwang commented 6 years ago

And this is also work for me.

    final wms = [persistor.createMiddleware()]..addAll(createMiddlewares());
    if (TangboleConfig.debug) {
      wms.add(LoggingMiddleware<AppState>.printer());
    }
djshanne commented 4 years ago

List<Middleware> mws, this solution worked for me, thanks.