I've got a simplified example below. In practice, I'm passing a list of data objects to a StatefulWidget. I want the Widget to copy the provided list into its state object which will then be filtered through future interactions. The filters use a type parameter so they know what fields they can work with in a callback, for example Filter<MyData>
.
So, I'm trying to create a Widget that is aware of the MyData
type so it can build the FilterChip Widgets using MyData fields. I tried to achieve this by adding a type parameter to both the StatefulWidget and its State class.
import 'package:flutter/material.dart';
/// Generic type information loss example
class MyWidget<T> extends StatefulWidget {
final List<T> things;
const MyWidget({Key? key, required this.things}) : super(key: key);
@override
_MyWidgetState createState() => _MyWidgetState<T>();
}
class _MyWidgetState<T> extends State<MyWidget> {
@override
Widget build(BuildContext context) {
List<T> things = widget.things; // Compiler error (IDE shows widget.things has a type of List<dynamic>)
return Container();
}
}
This code results in:
Error: A value of type 'List<dynamic>' can't be assigned to a variable of type 'List<T>'.
So what I don't understand is, why does things
in the StatefulWidget
class have a type of List<T>
, but when referenced through the widget
property of the class extendingState<MyWidget>
, widget.things
has a type of List<dynamic>
.
And, as a result, any code in the state class that needs to be aware of the type now breaks. At runtime, the filter callbacks result in errors like:
type '(MyData) => bool' is not a subtype of type '(dynamic) => bool'