How to enforce Implements constraint on generic type T in generic Dart method?

1,073

Problem

It seems like I can't set an implements constraint on type T, only an extends. For example <T implements IModel does not work but works.

This is not a problem. You can safely use <T extends IModel>, even for classes that implements IModel:

abstract class Abstract {}

class Concrete implements Abstract {}

void function<T extends Abstract>(T value) {
  print(value);
}

void main() {
  function<Concrete>(Concrete()); // works
}
Share:
1,073
EggBender
Author by

EggBender

Updated on December 23, 2022

Comments

  • EggBender
    EggBender over 1 year

    What I'm trying to achieve

    I am trying to create a generic Dart method that takes a generic type T where T has to implement class IModel. However,

    Problem

    It seems like I can't set an implements constraint on type T, only an extends. For example <T implements IModel does not work but <T extends IModel> works.

    Code

    IModel.dart which serves as an interface:

    class IModel {
      IModel();
    
      factory IModel.fromJson(Map<String, dynamic> json) {
        return IModel();
      }
    
      Map<String, dynamic> toJson() => {};
    
      IModel clone() {
        return IModel();
      }
    }
    
    

    MyModel.dart, an example that implements IModel:

    import 'dart:core';
    import 'package:.../helpers/DateTimeHelper.dart';
    import 'package:.../helpers/StringHelper.dart';
    import 'package:.../models/IModel.dart';
    
    class MyModel implements IModel {
      String id;
      String name;
      String companyId;
      String projectId;
      String description;
      DateTime created;
      DateTime updated;
    
      MyModel({this.id, this.name, this.description, this.created, this.updated, this.companyId, this.projectId});
    
      factory MyModel.fromJson(Map<String, dynamic> json) {
        return MyModel(id: json["id"], name: json["name"], created: DateTime.parse(json["created"]), updated: DateTime.parse(json["updated"]), description: json["description"], companyId: json["companyId"], projectId: json["projectId"]);
      }
    
      Map<String, dynamic> toJson() => {
            "Id": id,
            "Name": name,
            "Description": description,
            "CompanyId": companyId,
            "ProjectId": projectId,
            "Created": created.toIso8601String(),
            "Updated": updated.toIso8601String()
          };
    
      MyModel clone() {
        return new MyModel(id: StringHelper.clone(id), companyId: StringHelper.clone(companyId), created: DateTimeHelper.clone(created), updated: DateTimeHelper.clone(updated), name: StringHelper.clone(name), projectId: StringHelper.clone(projectId), description: StringHelper.clone(description));
      }
    }
    
    

    ModelHelper.dart with the generic method:

    import 'dart:convert';
    
    import 'package:.../models/IModel.dart';
    
    // 'T implements IModel' not working, but 'T extends IModel' does as constraint.
    abstract class ModelHelper {
      static List<T> listFromJson<T implements IModel>(String json) {
        List l = jsonDecode(json)["data"];
        var models = l.map((m) => T.fromJson(m)).toList();
        return models;
      }
    }
    
    

    Additional questions/conclusion

    Are implements constraints not supported in Dart? Do all T classes simply have to extend IModel?