Reputation: 53
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
Upvotes: 5
Views: 2315
Reputation: 1074595
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:
Implement toJSON
on your Test
class and return an object with a replacement for children
(probably an array of arrays), or
Implement a subclass of Map
that has toJSON
and use that in Test
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))
Upvotes: 7