16

I've got a Map<string, string> variable in typescript:

let m = Map<string, string>().set('tag', 'v1');

I want to convert to json string representation:

'{"tag": "v1"}'

I've tried 3 different ways. First is to use m.toString(). Second is using JSON.stringify(m). Both returned {}. I've even tried to convert the Map to a javascript object first and then convert to string:

function MapToString(map): string {
  let ro = {};
  Object.keys(map).forEach( key => {
    ro[key] = map[key];
  });
  return JSON.stringify(ro);
}

s = MapToString(m);

This returned {} as well when I tried to print it in the console.

5

6 Answers 6

13

Surprised this wasn't mentioned yet:

let m = new Map().set('tag', 'v1').set('foo', 'bar')

JSON.stringify(Object.fromEntries(m))

Seems to me the most readable solution.

Sign up to request clarification or add additional context in comments.

Comments

12

I eventually gave up on using es6 Map and switched to TSMap, on which tags.toJSON() works.

Comments

12

Readable? No, but it works

JSON.stringify(
  Array.from(
    new Map().set('tag', 'v1').set('foo', 'bar').entries()
  )
  .reduce((o, [key, value]) => { 
    o[key] = value; 

    return o; 
  }, {})
)

Like @james-hay pointed out, you have a typo that probably makes the object empty

3 Comments

With [key, val] instead of the parameter e it would be more readable IMO. :-)
yeah, I usually forget that nice new destructuring assignment :-) Thanks.
Doesn't do deep toString, tho.
12

Although it does not directly answer your question: when I had the same problem, I reconsidered my use of Map and went for plain JavaScript objects. Since JSON always needs strings as keys, one of Map's main advantages (keys of any type) are lost anyway.

Another advantage of Map is that they allow a nice type signature, like Map<String, Array<String>>. But here TypeScript's "index signatures" provide exactly this for plain JavaScript objects and even allow a name for keys:

interface CityLists {
    [postcode: string]: Array<string>
};

This can be used almost like a Map (with different syntax, of course) and it directly converts to JSON even when nested. I think the latter is quite important when you convert an object tree to JSON where maps can be nested somewhere deep down in other arbitrary objects and arrays.

Alternatively, TypeScript also has the type Record<K, T> for this use-case: a plain object used as a typed map. In the above example, I could write:

let cityLists: Record<string, Array<string>>;
cityLists["capitals"] = ["Rome", "Paris", "Berlin"];

Comments

0

In Nativescript with lib es2015 I can do:

From Object to string:

// no need to import JSON
let fooInString = JSON.stringify(this.mapObject.subMap);

From string to Object:

// no need to import JSON
let fooInObject = JSON.parse(fooInString);

Happy Coding!

Comments

-1

While this seems to be a typo as indicated in other answers, this problem can occur when ES6 and vanilla JS are used together in the same project. JS won't recognise the ES6 map and convert it to an empty object "{}".

A quick workaround is to use a serialiser/deserialiser whenever persisting ES6 maps in a JS object

ES6 to JS

convertTSMapToJSObj(tsMap) {
    const jsObj = {};
    tsMap.forEach(function (value, key) {
        jsObj[key] = value;
    });
    return jsObj;
}

JS to ES6

convertJSObjToTSMap(jsObj) {
    const tsMap = new Map();
    const arrayOfMapEntries = new Map<any, any>(Object.entries(jsObj);
    for (const [key, value] of arrayOfMapEntries.entries()) {
        tsMap.set(key, value);
    }
    return tsMap;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.