Solved: How do you cast data from Firebase to a fully typed Map?

Question

Asked by John M on January 04, 2022 (source).

I have data from Firebase that looks something like this:

{
    "foo": {
        1: true,
        2: false
    },
    "bar": {
        3: true,
        4: false
    }
}

If I'm not mistaken, this should be a Map<String, Map<int, bool>>. I'm trying to use this function to safely cast it:

T castWithDefaultValue<T> (val, T defaultValue) => val is T ? val : defaultValue;

var castData = castWithDefaultValue<Map<String, Map<int, bool>>>(dataFromFirebase, {});

But it fails, always returning the default value. The only types I can get to work for either the key or the value are Object? and dynamic, but I want more type safety. How do I get it to what I want it to be?

Answer

Question answered by mmcdon20 (source).

I don't think you can cast a nested data structure like this. See this discussion for more info.

The best I think you can do is deep copy the data structure into a new collection and cast each part as you are copying. In this case you could do something like:

void main() {
  // intentionally removing type data for example
  dynamic data = <dynamic, dynamic>{
    "foo": <dynamic, dynamic>{1: true, 2: false},
    "bar": <dynamic, dynamic>{3: true, 4: false},
  };

  final deepCopy = {
    for (final entry in data.entries)
      entry.key as String: {
        for (final subEntry in entry.value.entries)
          subEntry.key as int: subEntry.value as bool,
      },
  };

  print(deepCopy);
  print(deepCopy.runtimeType);
}
DART FIREBASE FIREBASE-REALTIME-DATABASE FLUTTER
SHARE: