How to pattern match the runtimeType of a freezed class?

76 Views Asked by At

I am implementing an infinite scroll list for a home feed in a Flutter app. The list contains different items that are rendered with different widgets. I use the freezed package to create domain models that I initialize with the response from an API. Now I need some way to differentiate the models to render the correct widget. I decided to create a general HomeFeedItem widget, that does the rendering.

class HomeFeedItem extends StatelessWidget {
  final dynamic item;

  const HomeFeedItem({Key? key, required this.item}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final Widget widget;

    switch (item.runtimeType) {
      case TodayDivider:
        widget = const TodayDivider();
      case DateDivider:
        widget = DateDivider(date: item.date);
      case CheckinCTA:
        widget = const CheckinCTA();
      case EntryPreview:
        widget = EntryPreview(
          id: item.id,
          title: item.title,
          summary: item.summary,
        );
      default:
        widget = const Text('Unknown item type');
    }

    return Column(
      children: [
        widget,
        const SizedBox(height: 24),
      ],
    );
  }
}

The issue is that for example of EntryPreview the runtimeType is _$EntryPreviewImpl, which is private. So this approach fails and every item is Text("Unknown item type")

I could add a getter to each model that returns a type. But I was wondering if there isn't a better way to pattern match the type of a freezed class.

1

There are 1 best solutions below

5
jamesdlin On BEST ANSWER

Doing:

switch (item.runtimeType) {
  case TodayDivider:
    ...

uses a constant pattern that compares the Type object returned by item.runtimeType for equality. Equality for Type objects is object identity; they compare equal only to themselves regardless of relationships between types.

You instead should use a variable pattern that matches item and not item.runtimeType:

    switch (item) {
      case TodayDivider _:
        widget = const TodayDivider();
      case DateDivider item:
        widget = DateDivider(date: item.date);
      case CheckinCTA _:
        widget = const CheckinCTA();
      case EntryPreview item:
        widget = EntryPreview(
          id: item.id,
          title: item.title,
          summary: item.summary,
        );
      default:
        widget = const Text('Unknown item type');
    }