Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stringify an object of the type Map

class test{
    name : string
    children : Map<string,string> =new Map()
    constructor(){
        this.name='KIANA'
        this.children.set('name','OTTO')
    }
}
var t = new test()
console.log(t)
console.log(JSON.stringify(t))

The result is:

test { children: Map { 'name' => 'OTTO' }, name: 'KIANA' }
{"children":{},"name":"KIANA"}

How can I get the whole data like:

{"children":{'name':'OTTO'},"name":"KIANA"}

or

{"children":['name':'OTTO'],"name":"KIANA"}

Or, does it has a simpler way to describe the relationship of 'key value' in JSON and TypeScript

like image 216
XILING Avatar asked Feb 08 '20 13:02

XILING


People also ask

Can you Stringify an object?

Stringify a JavaScript ObjectUse the JavaScript function JSON.stringify() to convert it into a string. const myJSON = JSON.stringify(obj); The result will be a string following the JSON notation.

Can I use JSON Stringify for map?

You cannot call JSON. stringify on Map or Set . You will need to convert: the Map into a primitive Object , using Object.

What does JSON Stringify () method do?

The JSON.stringify() method converts a JavaScript value to a JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.

How do you compare object and map?

In Object, the data-type of the key-field is restricted to integer, strings, and symbols. Whereas in Map, the key-field can be of any data-type (integer, an array, even an object!) In the Map, the original order of elements is preserved. This is not true in case of objects.


1 Answers

Preface: Class names should start with an uppercase character, so I've changed test to Test in the below.

Since Map isn't stringify-able by default, you have at least three choices:

  1. Implement toJSON on your Test class and return an object with a replacement for children (probably an array of arrays), or

  2. Implement a subclass of Map that has toJSON and use that in Test

  3. Implement a replacer that you use with JSON.stringify that handles Map instances.

While #1 works, it means you have to edit your toJSON method every time you add or remove properties from Test, which seems like a maintenance issue:

class Test {
  name: string
  children: Map<string, string> = new Map()
  constructor() {
    this.name = 'KIANA'
    this.children.set('name', 'OTTO')
  }
  toJSON() {
    return {
      name: this.name,
      children: [...this.children.entries()]
    }
  }
}
var t = new Test()
console.log(JSON.stringify(t))

Live Example:

class Test {
  name/*: string*/
  children/*: Map<string, string>*/ = new Map()
  constructor() {
    this.name = 'KIANA'
    this.children.set('name', 'OTTO')
  }
  toJSON() {
    return {
      name: this.name,
      children: [...this.children.entries()]
    }
  }
}
var t = new Test()
console.log(JSON.stringify(t))

[...this.children.entries()] creates an array of [name, value] arrays for the map.

But I prefer #2, a JSON-compatible Map:

class JSONAbleMap extends Map {
  toJSON() {
    return [...this.entries()]
  }
}

...which you then use in Test:

class Test {
  name: string
  children: Map<string, string> = new JSONAbleMap()
  constructor() {
    this.name = 'KIANA'
    this.children.set('name', 'OTTO')
  }
}
var t = new Test()
console.log(JSON.stringify(t))

Live Example:

class JSONAbleMap extends Map {
  toJSON() {
    return [...this.entries()]
  }
}

class Test {
  name/*: string*/
  children/*: Map<string, string>*/ = new JSONAbleMap()
  constructor() {
    this.name = 'KIANA'
    this.children.set('name', 'OTTO')
  }
}
var t = new Test()
console.log(JSON.stringify(t))

Or #3, a replacer function you use with JSON.stringify:

function mapAwareReplacer(key: string|Symbol, value: any): any {
    if (value instanceof Map && typeof value.toJSON !== "function") {
        return [...value.entries()]
    }
    return value
}

...which you use when calling JSON.stringify:

console.log(JSON.stringify(t, mapAwareReplacer))

Live Example:

function mapAwareReplacer(key, value) {
    if (value instanceof Map && typeof value.toJSON !== "function") {
        return [...value.entries()]
    }
    return value
}

class Test {
  name/*: string*/
  children/*: Map<string, string>*/ = new Map()
  constructor() {
    this.name = 'KIANA'
    this.children.set('name', 'OTTO')
  }
}
var t = new Test()
console.log(JSON.stringify(t, mapAwareReplacer))
like image 71
T.J. Crowder Avatar answered Sep 28 '22 16:09

T.J. Crowder