JSON only supports: strings, numbers, booleans, null and arrays and plain objects with those as values/properties. That's it. So, no other type of object that is comprised of anything more than that is directly supported by JSON.
You have to either manually convert your object to something that can be represented with these basic types in JSON or find some other way to represent your object. The data within an object like a Map with simple values/indexes could be manually put into JSON form (perhaps in an array of objects or an array of arrays), but converting it back into a Map when deserialized will have to be done manually.
You can see the types that JSON supports here: https://www.json.org/
This means that no custom object type, even if its instance data is only composed of the above types will deserialize into the proper object type. This would include even something like a Date
or a Regex
and certainly includes any non-plain object such as Set
, or Map
.
It is possible to manually convert your data into something that is JSON serializable and then manually deserialize into the appropriate object. For example, you could serialize a non-nested Map
and Set
that only contains legal keys and values like this:
function serialize(mapOrSet) {
if (mapOrSet instanceof Map) {
// convert Map into 2D array
// [[key1, val1], [key2, val2], ....]
let data = [];
for (const [key, value] of mapOrSet) {
data.push([key, value]);
}
return JSON.stringify({
_customType: "Map",
_data: data
});
} else if (mapOrSet instanceof Set) {
return JSON.stringify({
_customType: "Set",
_data: Array.from(mapOrSet);
});
} else {
throw new TypeError("argument to serialize() must be Map or Set");
}
}
Then, you'd have to have a custom deserializer that could detect objects with the _customType
property on them and call an appropriate deserializer function to convert the plain JSON into the appropriate custom object types. You could even make the system extensible by having objects support their own serializing and deserializing functions, using some sort of _customType
property to identify the appropriate class name to invoke. Of course, both source and destination would have to have the appropriate serialize and deserialize extensions present to make it work properly.