如何将数据从 Firebase 转换为完全类型化的地图?

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

我有来自 Firebase 的数据,看起来像这样:

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

如果我没记错的话,这应该是Map<String, Map<int, bool>>。我正在尝试使用这个函数来安全地转换它:

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

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

但是失败了,总是返回默认值。我可以为键或值工作的唯一类型是 Object?dynamic,但我想要更多类型安全性。我怎样才能达到我想要的效果?

当我有一个只有字符串值的快照时,获取它们是一个两步过程:

var data = snapshot.val() as Map<String,dynamic>;
var values = Map<String, String>.from(data);

第一行是常规转换,第二行是数据转换。另见:

我不确定是否可以一次性完成整个对象的转换,但如果可以的话,它会是这样的:

Map<String, Map<int, bool>>.from(dataFromFirebase)

这似乎至少在这里起作用:https://dartpad.dev/9dad7a0e39add2c690b3b54afe284005

我认为您不能像这样强制转换嵌套数据结构。 See this discussion for more info.

我认为你能做的最好的事情就是将数据结构深复制到一个新的集合中,并在复制时转换每个部分。在这种情况下,您可以执行以下操作:

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);
}