Declaring expected variable type cause error: type '(Map<String, dynamic>) => University' is not a subtype of type '(dynamic) => dynamic' of 'f'

306

On reddit someone said:

I think because when you decode and parse JSON, it gives you a general Dart object, not directly a map. So you have to cast it as a Map afterwards.

Your fromJson method is expecting a Map<String, dynamic> argument, but you are passing an object (the decoded JSON) which you labeled as Map<String, dynamic>. I think it would work if you did

fromJson(x as Map<String,dynamic>)

instead of

fromJson(Map<String, dynamic> x)

dynamic or just "x" (which will be inferred as dynamic) works because having a dynamic type could mean anything and removes the strict checking

And in stackoverflow there is an explanation like that:

In Dart, the element type of a list is provided when the list is created, and it is kept as part of the list value. Every type you add an element to the list, it is checked to be of that type. This is unlike Java where generic type arguments are erased at runtime.

That means that a Dart List is not the same as a List<Map<String, dynamic>>, even if both lists contains only instances of Map<String, dynamic>>. For example, you can add an integer to the former and not to the latter.

A JSON list can contain any JSON value. In this case, your list contains only values that are maps, but that could be a coincidence. The JSON parser does not check the source code first to see if the list contains only one kind of objects, instead it just creates a List and puts the elements into that. The created list is mutable, so someone might add an integer to that list after it has been returned. That code would break if the parser made the list a List<Map<String, dynamic>> instead.

So, your list is a List because all JSON lists created by jsonParse are that ... and it would be a breaking change to make them anything else.

Thanks for the responses. My question has been answered. I am checking this post as a correct answer.

Share:
306
Hazar Belge
Author by

Hazar Belge

api/me Flutter Developer. Student at Galatasaray University. VueJS and NodeJS learner. Ex Game Developer.

Updated on December 31, 2022

Comments

  • Hazar Belge
    Hazar Belge over 1 year

    I am using this logic to convert json data to a custom University model.

    import 'dart:convert';
        
    class UniversityWrapper {
      UniversityWrapper({
        this.isSuccess,
        this.message,
        this.data,
      });
    
      final bool isSuccess;
      final dynamic message;
      final List<University> data;
    
      factory UniversityWrapper.fromRawJson(String str) => UniversityWrapper.fromJson(json.decode(str));
    
      String toRawJson() => json.encode(toJson());
    
      factory UniversityWrapper.fromJson(Map<String, dynamic> json) => UniversityWrapper(
        isSuccess: json["is_success"],
        message: json["message"],
        data: json["data"] == null ? null : List<University>.from(json["data"].map((Map<String, dynamic> x) => University.fromJson(x))),
      );
    
      Map<String, dynamic> toJson() => <String, dynamic>{
        "is_success": isSuccess,
        "message": message,
        "data": data == null ? null : List<dynamic>.from(data.map((University x) => x.toJson())),
      };
    }
    
    class University {
      University({
        this.id,
        this.name,
        this.cityId,
      });
    
      final int id;
      final String name;
      final int cityId;
    
      factory University.fromRawJson(String str) => University.fromJson(json.decode(str));
    
      String toRawJson() => json.encode(toJson());
    
      factory University.fromJson(Map<String, dynamic> json) => University(
        id: json["id"],
        name: json["name"],
        cityId: json["city_id"],
      );
    
      Map<String, dynamic> toJson() => <String, dynamic>{
        "id": id,
        "name": name,
        "city_id": cityId,
      };
    }
    

    The problem is in this line:

    data: json["data"] == null 
       ? null 
       : List<University>.from(json["data"].map((Map<String, dynamic> x) => University.fromJson(x))),
    

    If I set x's type as dynamic or nothing, there isn't an error. Like Example 1 and Example 2:

    Example 1:

    data: json["data"] == null 
           ? null 
           : List<University>.from(json["data"].map((dynamic x) => University.fromJson(x))),
    

    Example 2:

    data: json["data"] == null 
          ? null 
          : List<University>.from(json["data"].map((x) => University.fromJson(x))),
    

    But the main question is, I don't understand why can't I set Map<String, dynamic> as a type of x. I think that I should be able to set it because University.fromJson method takes Map<String, dynamic>.

    The method University.fromJson:

      factory University.fromJson(Map<String, dynamic> json) => University(
        id: json["id"],
        name: json["name"],
        cityId: json["city_id"],
      );
    

    The error:

    E/flutter ( 4780): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type '(Map<String, dynamic>) => University' is not a subtype of type '(dynamic) => dynamic' of 'f'
    E/flutter ( 4780): #0      new UniversityWrapper.fromJson (package:hb/models/university.dart:21:76)
    E/flutter ( 4780): #1      _ProfilePageState.loadData (package:hb/ui/pages/profile.dart:118:66)
    E/flutter ( 4780): <asynchronous suspension>
    E/flutter ( 4780): 
    

    Edit 1: Example JSON Data:

     {   
        "is_success": true,   
        "message": null,   
        "data": [
            {
              "id": 1,
              "name": "Abant İzzet Baysal Üniversitesi",
              "city_id": 14
            },
            {
              "id": 118,
              "name": "Acıbadem Üniversitesi",
              "city_id": 34
            },
            {
              "id": 4,
              "name": "Adıyaman Üniversitesi",
              "city_id": 2
            },
            {
              "id": 6,
              "name": "Afyon Sağlık Bilimleri Üniversitesi",
              "city_id": 3
            }
        ]
     }
    
    • Akif
      Akif over 2 years
      Can you please share the sample JSON too?
    • Hazar Belge
      Hazar Belge over 2 years
      I shared info. But I don't think the problem at the parsing process.
    • Akif
      Akif over 2 years
      Ok, there is a good explanation of your question here: stackoverflow.com/a/55577750/10659482
    • Akif
      Akif over 2 years
      dynamic is not the same as a Map<String, dynamic>.
    • Hazar Belge
      Hazar Belge over 2 years
      Thanks a lot @Akif