'Why does Dart expect a value of type dynamic instead of T in a generic class [duplicate]

So I'm working on a flutter app and created a generic dropdownbutton class that I want to fill with objects from a database. The dropdownbutton takes a list of these objects, a function to get the display values of them and then shows these display values in the dropdownmenu. Here is the generic dropdownbutton class:

class GenericDropdownButton<T> extends StatefulWidget {
  T? _selectedValue;
  final List<T> _values;
  final String Function(T value) _displayValueGetter;

  GenericDropdownButton(this._values, this._displayValueGetter, {Key? key})
      : super(key: key);

  @override
  State<GenericDropdownButton> createState() => _GenericDropdownButtonState();
}

class _GenericDropdownButtonState<T> extends State<GenericDropdownButton<T>> {
  @override
  Widget build(BuildContext context) {
    return DropdownButton<T>(
      value: widget._selectedValue,
      items: widget._values.map((T value) {
        return DropdownMenuItem<T>(
          value: value,
          child: Text(widget._displayValueGetter(value)),
          //child: Text(value.toString()),
        );
      }).toList(),
      onChanged: (T? newValue) {
        setState(() {
          widget._selectedValue = newValue;
        });
      },
    );
  }
}

I created a simple class for demonstration purposes to pass to the dropdownbutton:

class TestClass {
  int id;
  String name;

  TestClass(this.id, this.name);
}

And I instantiate a dropdownbutton like this:

class TestPage extends StatefulWidget {
  const TestPage({Key? key}) : super(key: key);

  @override
  State<TestPage> createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Generic dropdown button test'),
      ),
      body: Column(mainAxisSize: MainAxisSize.max, children: <Widget>[
        GenericDropdownButton<TestClass>(
          <TestClass>[TestClass(1, 'One'), TestClass(2, 'Two')],
          (TestClass t) => t.name
        ),
      ]),
    );
  }
}

When I execute this, I get the following error:

Expected a value of type '(dynamic) => String', but got one of type '(TestClass$) => String'

Which corresponds to this line:

child: Text(widget._displayValueGetter(value)),

So as far as I understand, dart expects the parameter 'value' to be of type 'dynamic', although it's clearly of type 'T' (in this case of type 'TestClass'), since '_displayValueGetter' is of type 'String Function(T)'. Why does dart expect that and how can I prevent dart from expecting that?



Solution 1:[1]

The type wasn't specified in createState which is why it's choosing to be dynamic.

Specify it like so:

@override
State<GenericDropdownButton<T>> createState() => _GenericDropdownButtonState<T>();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Josteve