Why isn't my sub class that implements/extends a parent class recognized as a sub type of the parent class in Dart Flutter?

446

I get the following error that the ProjectModel parameter in a function I'm trying to pass, does not count as being an IIdentified.

I don't think you actually pasted that function but I can properly still guess what happen. The problem is that you have made a function with the signature:

(ProjectModel) => void

And want to use it as argument where it takes a (IIdentified) => void. This is a common problem when we are talking inheritance and method arguments since it can seem a little backward.

But, the problem is that if you have a method which can take a IIdentified as argument, it should be able to take all kind of IIdentified and not just a specific kind of IIdentified. You cannot just give a function which can handle ProjectModel and assume it would be able to handle some other subclass of IIdentified.

If we are instead was going to have the following:

() => ProjectModel

Then this would be a valid subtype of () => IIdentified since we are allowed to return a more specific kind of IIdentified.

Share:
446
EggBender
Author by

EggBender

Updated on December 26, 2022

Comments

  • EggBender
    EggBender over 1 year

    I have the ProjectModel class which implements IIdentified class. But during runtime, I get an error that ProjectModel is not a sub type of IIdentified although it implements it. I have also tried to use extend instead of implements in ProjectModel but that didn't help either. How can I work with interfaces in Dart Flutter so that a Widget can have a generic type that fullfills a certain interface or contract?

    Parent class IIdentified I use like an interface:

    abstract class IIdentified {
      String id;
      String name;
    }
    
    

    Sub class implementing (also tried extending) parent class IIdentified:

    
    class ProjectModel implements IIdentified {
      String id;
      DateTime created;
      DateTime updated;
      bool hasMileage;
      bool hasAllowance;
      bool hasTravelTime;
      String name;
      String description;
      DateTime startDate;
      DateTime endDate;
      DateTime completed;
      double estimatedTime;
      double absentTime;
      double presentTime;
      Status status;
      String companyId;
      String customerId;
    
      ProjectModel(
          {this.id,
          this.created,
          this.updated,
          this.hasMileage,
          this.hasAllowance,
          this.hasTravelTime,
          this.name,
          this.description,
          this.startDate,
          this.endDate,
          this.completed,
          this.estimatedTime,
          this.absentTime,
          this.presentTime,
          this.status,
          this.companyId,
          this.customerId});
    

    I get the following error that the ProjectModel parameter in a function I'm trying to pass, does not count as being an IIdentified:

    The following _TypeError was thrown building LoaderDropdownButton<ProjectModel>(dirty, dependencies: [MediaQuery], state: LoaderDropdownButtonState<IIdentified>#f2031):
    type '(ProjectModel) => void' is not a subtype of type '(IIdentified) => void'
    

    The generic widget only accepting type T extends IIdentified:

    class LoaderDropdownButtonState<T extends IIdentified> extends State<LoaderDropdownButton<T>> {
      double displayWidth;
      double displayHeight;
    
      @override
      void initState() {
        init();
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        setDisplayDimensions();
        return Container(
          padding: EdgeInsets.only(left: 25),
          color: widget.enableSelect ? themeConfig.dropButtonBg : themeConfig.dropButtonDisabledBg,
          child: Theme(
            data: ThemeData(canvasColor: Color(0xFFC5C5C5)),
            child: DropdownButtonHideUnderline(
              child: new DropdownButton<T>(
                  hint: Row(
                    children: <Widget>[
                      Expanded(
                        flex: 10,
                        child: Container(
                          alignment: Alignment.center,
                          margin: EdgeInsets.only(top: 2),
                          child: Text(
                            widget.text,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(
                              color: widget.enableSelect
                                  ? themeConfig.dropButtonFg
                                  : themeConfig.dropButtonDisabledFg,
                              fontSize: displayWidth * 0.045,
                            ),
                          ),
                        ),
                      ),
                      Flexible(
                        flex: 2,
                        child: Container(
                          margin: EdgeInsets.only(top: 5),
                          child: Icon(
                            Icons.keyboard_arrow_down,
                            color: widget.enableSelect
                                ? themeConfig.dropButtonFg
                                : themeConfig.dropButtonDisabledFg,
                          ),
                        ),
                      )
                    ],
                  ),
                  iconSize: 0,
                  isExpanded: true,
                  items: buildItems(),
                  onChanged: widget.onChange),
            ),
          ),
        );
      }
    
      void init() {
        displayWidth = 1;
        displayHeight = 1;
      }
    
      setDisplayDimensions() {
        if (displayWidth == 1) displayWidth = MediaQuery.of(context).size.width;
        if (displayHeight == 1) displayHeight = MediaQuery.of(context).size.height;
      }
    
      List<DropdownMenuItem<T>> buildItems() {
        return widget.data.map((dataItem) {
          return DropdownMenuItem<T>(
            value: dataItem,
            child: Text(dataItem.name),
          );
        }).toList();
      }
    }
    
    

    Why doesn't ProjectModel pass as an IIdentified when it implements/extends it? How do you work with interfaces/contracts in generic widgets?

    Thanks!