Dart correct way to specify generic argument type on callback function

Issue

I’vo got a strange error, for a class similar to this one:

class UpdatableListPage<T> extends ConsumerStatefulWidget {
  final StateNotifierProvider<UpdatableNotifier, List<T>> provider;
  final Widget Function(T t) callbackWidget;

[...]

  @override
  _UpdatableListPageState<T> createState() => _UpdatableListPageState<T>();
}


class _UpdatableListPageState<T> extends ConsumerState<UpdatableListPage> {

 @override
  Widget build(BuildContext context) {
    // Here the IDE said modelList is dynamic
    var modelList = ref.watch(widget.provider);
    [...]
    ListView(
                key: _refreshKey,
                shrinkWrap: true,
                scrollDirection: widget.scrollDirection,
                children: [
                  for (final product in modelList as List<T>) widget.callbackWidget.call(product),
              ],

  }

}

And I call the funciton as:

UpdatableListPage<RsMsgMetaData>(
          userPostsProvider,
          callbackWidget:  (t) => PostTeaserCard(t,),
        ),

Where PostTeaserCard is a statefull Widget that recieve a RsMsgMetaData object as parameter.

The IDE say that everything is Ok but at run time, I got the following error:

type '(RsMsgMetaData) => PostTeaserCard' is not a subtype of type '(dynamic) => Widget'`

Seems like callbackWidget acts as (dynamic) => Widget function, but anyway… Should this function be compatible with the function signature of the anonymous function, right?

I don’t know what is going on with this…

Solution

You wrote:

class _UpdatableListPageState<T> extends ConsumerState<UpdatableListPage> {

which is equivalent to:

class _UpdatableListPageState<T> extends ConsumerState<UpdatableListPage<dynamic>> {

Consequently, the type of _UpdatableListPageState<T>.widget.callbackWidget is Widget Function(dynamic t). You cannot pass a PostTeaserCard Function(RsMsgMetaData) for a Widget Function(dynamic) because the latter is callable with any argument, but the function you actually passed can be called only with an RsMsgMetaData argument.

To fix this, fix your _UpdatableListPageState class declaration to avoid the implicit use of dynamic and to fully depend on T:

class _UpdatableListPageState<T> extends ConsumerState<UpdatableListPage<T>> {

This probably will fix the type for modelList to List<T> instead of List<dynamic>.

Enabling the strict-raw-types check in your analysis_options.yaml should help catch this kind of error in the future.

Answered By – jamesdlin

Answer Checked By – Candace Johnson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.