skip to Main Content

I need to cast a List and a Map of unknown types to specific types. If the List or Map are not empty all is well. But if they are ever empty I get a cast error.

When list is empty:

final list = [];
final result = list as List<Map<String, dynamic>?>;

Output

type 'List<dynamic>' is not a subtype of type 'List<Map<String, dynamic>?>' in type cast

When Map is empty:

final map = {};
final result = map as Map<String, dynamic>;

Output

type '_Map<dynamic, dynamic>' is not a subtype of type 'Map<String, dynamic>' in type cast

For context: I’m fetching data from firebase. The DocumentSnaphot.data() of the firebase package returns an Object?. Therefore I have no control over what type the data is. Hence the casting…

2

Answers


  1. Chosen as BEST ANSWER

    For casting lists you should use List<T>.from(list as List), List.cast or List.castFrom.

    For casting maps you should use Map<T>.from(map as Map) or Map.castFrom.

    class FakeDocumentSnapshot {
      Object? data() {
        return {
          'list': [{}]
        };
      }
    }
    
    final snapshot = FakeDocumentSnapshot();
    
    final data = Map<String, dynamic>.from((snapshot.data() ?? {}) as Map);
    
    final list = (List.from(data['list'] ?? [])..removeWhere((e) => e == null));
    
    final result = list
        .map((x) => Map<String, dynamic>.from(x as Map))
        .toList();
    

    (I answered my own question)


  2. You can use pattern matching to respond to the different types returned by Firebase.

    Here’s an example:

    void parseData(Object? data) {
      switch (data) {
        /// Handle empty list.
        case []:
          log("Received empty list.");
        /// Matches a list of integers.
        case List<int> list:
          log("Received integer list: $list");
        /// Matches when it's a list of maps whose key is of type String, but value
        /// can be any type (dynamic).
        case List<Map<String, dynamic>> list:
          log("Received list of maps: $list");
        /// Handle unexpected data type.
        default:
          log("Unknown data type: ${data.runtimeType}");
      }
    }
    

    You can then use the parseData function to parse your Firebase data:

    Object? invalid = 1;
    
    Object? dataList = [1, 2, 3];
    
    Object? dataListOfMap = [
      {
        "key": [1, 2, 3],
      },
    ];
    
    parseData(invalid);       /// 'Unknown data type: int'.
    parseData(dataList);      /// 'Received integer list: [1, 2, 3]'.
    parseData(dataListOfMap); /// 'Received list of maps: [{key: [1, 2, 3]}]'.
    

    Dart also provides the is operator to first check if some reference is of a certain type:

    if (myInstance is SomeType) ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search