Home > OS >  Why is the type '($someObject$) => $someWidget$' not a subtype of type '(dynamic)
Why is the type '($someObject$) => $someWidget$' not a subtype of type '(dynamic)

Time:01-17

I have an flutter app that throws this error, at a specific action in the application:

======== Exception caught by widgets library =======================================================
The following _TypeError was thrown building DataFetcher<CompleteVocabularyCollection>(dirty, state: _DataFetcherState<CompleteVocabularyCollection>#da61b):
type '(CompleteVocabularyCollection) => DetailsDisplay' is not a subtype of type '(dynamic) => Widget'

The relevant error-causing widget was: 
  DataFetcher<CompleteVocabularyCollection> DataFetcher:file://***/lib/screens/details/details.dart:56:18
When the exception was thrown, this was the stack: 
#0      _DataFetcherState.build (***/components/data_fetcher.dart:60:31)
[...]

Snippet from details.dart:

// [...]
DataFetcher<CompleteVocabularyCollection>(
            loadData: () async {
              CompleteVocabularyCollection? vocabularyCollection =
                await widget.futureCollection;
              if (vocabularyCollection == null) {
                throw NoDataException();
              }
              return vocabularyCollection;
            },
            loadingWidget: LoadingDisplay(
              infoText: widget.importMode ? "Reading file..." : "Loading data...",
            ),
            one rror: (exception) {
              String error = "Not available";

              if (exception is FilePickingAbortedException) {
                Navigator.pop(context);
              } else if (exception is NoDataException) {
                error = "No data found. That means usually means, "
                    "that the requested Vocabulary Collection does not exist.";
              } else if (exception is BrokenFileException) {
                error = "The provided JSON-File is not in the correct format.";
              } else {
                error = exception.toString();
              }

              return PlaceholderDisplay(
                icon: Icons.error,
                headline: "An error occurred",
                moreInfo: "More info:\n$error");
            },
            onFinished: (data) {
              return DetailsDisplay(vocabularyCollection: data, importMode: widget.importMode);
            },
        )
// [...]

data_fetcher.dart file:

import 'package:flutter/material.dart';

import '../models/data_fetching_state.dart';

class DataFetcher<T> extends StatefulWidget {
  final Future<T> Function() loadData;
  final Widget loadingWidget;
  final Widget Function(Object exception) one rror;
  final Widget Function(T data) onFinished;

  const DataFetcher(
      {Key? key,
      required this.loadData,
      required this.loadingWidget,
      required this.onError,
      required this.onFinished})
      : super(key: key);

  @override
  State<DataFetcher> createState() => _DataFetcherState<T>();
}

class _DataFetcherState<T> extends State<DataFetcher> {
  final DataFetchingState _state = DataFetchingState<T>();
  
  // [...] The code here is not interresting for the exception
  
  @override
  Widget build(BuildContext context) {
    Widget resultWidget;

    switch(_state.state) {
      case LoadingState.initial:
        resultWidget = const Text("Loading not started. Will be started soon.");
        break;
      case LoadingState.loading:
        resultWidget = widget.loadingWidget;
        break;
      case LoadingState.error:
        resultWidget = widget.onError(_state.exception);
        break;
      case LoadingState.finished:
        resultWidget = widget.onFinished(_state.data); // Here the exception occurs
        break;
    }

    return resultWidget;
  }
}

The definition of the DetailsDisplay looks like this:

class DetailsDisplay extends StatelessWidget {

and the CompleteVocabularyCollection is just a normal dart class.

So if I look through all this, I came up that (CompleteVocabularyCollection) => DetailsDisplay is a subtype of (dynamic) => Widget, because CompleteVocabularyCollection is just a normal class (so it should be a subtype of dynamic) and DetailsDisplay is a widget. So whats wrong?

CodePudding user response:

I believe this is because dynamic is a type of itself that can hold a variable of any type. This behavior is enforced at run time, so it doesn't mean that any type extends dynamic.
So the problem is not with DetailsDisplay, but rather with CompleteVocabularyCollection not being a subtype of dynamic.

CodePudding user response:

I'm not entirely sure why it happens but replacing

        onFinished: (data) {
          return DetailsDisplay(vocabularyCollection: data, importMode: widget.importMode);
        },

with

        onFinished: (dynamic data) {
          return DetailsDisplay(vocabularyCollection: data, importMode: widget.importMode);
        },

might solve it. I tried to reproduce your problem with this minimal example and I got the same error when I left out the dynamic. It works fine as written:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: MyApp<String>(onFinished: (dynamic c)=> Text(c))));
}

class MyApp<T> extends StatefulWidget {

  final Widget Function(T data) onFinished;

  const MyApp({super.key, required this.onFinished});

  @override
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
            body: widget.onFinished('test')
    );
  }
}

It seems it doesn't really do much with the generic type T and considers onFinished to always require a dynamic parameter. I don't really know why

  • Related