[SalesForce] (Lightning Component) sObject map keys turn into strings when passed from Apex to Javascript

My Apex controller returns a map<Account, list<String>> map type to my Lightning JS controller. But when I access it in my component's JS controller, the map turns into an object!

This unwanted conversion creates a few issues:

  1. Map methods like mapName.keys() don't work.

  2. The object isn't iterable, eg with for(var [key, value] of myMap.entries()

  3. In JS, unlike maps, objects can only have strings/symbols as keys. Which explains why my Apex map's sObject keys are now strings!

When I just retrieve a list of sObjects in my component controller, they are successfully stored as an object array, with the appropriate notation/syntax, ie:

{Id: "012345678912345", Name: "ABC Co"}

But in this former-map-turned-object, the sObject key has been stringified into something I can't use JSON.parse() on, ie:

[Account (Id:012345678912345, Name:ABC Co)]

Which is strange because according to this doc,

Return results from a server-side controller to a client-side controller using the return statement. Results data must be serializable into JSON format.

What am I missing here?

Best Answer

JSON and ES6 Maps just don’t play well together. You basically cannot natively deserialise a Apex controller returned JSON into a Map. If you want to iterate over the keys in the JS object you could just use the for(key in o) syntax

var jsObject = JSON.parse('{!acountMap}');

In the above JS snippet the variable jsObject is NOT an ES6 Map. It can only be deserialised to a plain JS object. The reverse is also NOT possible. JSON.stringify() on a ES6 Map won't do any thing. i.e. you cannot serialise an ES6 Map to a JSON because of the obvious reason that Object keys have to be strings and a Map key can be any Object.

Also, on the server side, Apex Map JSON serialisation is only supported when the Keys are primitive data types. See the last bullet point in Apex Map considerations in the docs

In summary you are doing the following 2 things Wrong

  1. On the server, You are trying to deserialise a Apex Map with a non-primitive type as Key
  2. On the browser, You are expecting to parse the JSON into an ES6 Map

Mark's Answer is a good way to work around point 1