Search code examples
dartdynamic

Dart error of adding Map to dynamic. Is it correct?


void main() {
  dynamic a = {'a' : 'a', 'b' : 'b', 'c':'c'};
  a['d'] = {'dd':'dd'};
}
DartPad caught unhandled _TypeError: TypeError: Instance of
'IdentityMap<String, String>': type 'IdentityMap<String, String>' is
not a subtype of type 'String'
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
4484:11   Object.throw_
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
15812:15  Object._failedAsCheck
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
15798:14  dart_rti.Rti.new._generalAsCheckImplementation
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
30307:63  _js_helper.IdentityMap.from._set
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
4722:16   Object._checkAndCall
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
4774:17   Object.callMethod
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
4777:17   Object.dsend blob:null/bf8ecf44-b93c-4548-ac5e-c180547a1b46
224:10                     main$0
blob:null/bf8ecf44-b93c-4548-ac5e-c180547a1b46 259:18                 
<fn> https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
43377:14  _rootRun
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
42207:14  async._CustomZone.new.run
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
43521:92  Object._runZoned
https://storage.googleapis.com/nnbd_artifacts/3.6.0/dart_sdk.js
43481:18  Object.runZoned
blob:null/bf8ecf44-b93c-4548-ac5e-c180547a1b46 257:20                 
Chain.capture Stack trace truncated and adjusted by DartPad...

And this one will be correct:

void main() {
  dynamic a = {'a' : {'aa' : 'aa'}, 'b' : 'b', 'c':'c'};
  a['d'] = {'dd':'dd'};
}

Solution

  • First, don't do this. I know it's normal in JS to have mixed-type data structures, but this is Dart, where that should be the exception.

    Second, you've got the typing wrong. Yes, your variable a is dynamic, but really you need the values to be dynamic, and instead, the map is inferred to be Map<String,String> since those are all of the initial values.

    To force the Map to hold anything for values, it must be declared that way:

    Map<String,dynamic> a = {...};
    

    Or the equivalent:

    var a = <String,dynamic>{ ... };