Map을 포함한 Object JSON stringify

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
interface MyType {
id: number;
cover: string;
outComes: Map<number, string>;
questions: Map<number, Map<number, string>>;
}

const stringify = (object: any) => {
for (const eachIdx in object) {
if (object[eachIdx] instanceof Map) {
object[eachIdx] = Array.from(object[eachIdx]);
stringify(object);
} else if (typeof object[eachIdx] == 'object') stringify(object[eachIdx]);
}
return JSON.stringify(object, null, 2);
};

const jsonString2ObjectWithMap = <ReturnType>(
jsonString: string
): ReturnType => {
const object = JSON.parse(jsonString);
console.log(`-------------변환전`);
console.log(object);

const jsonstringToObject = (object) => {
for (const eachIdx in object) {
if (
object[eachIdx] instanceof Array &&
object[eachIdx].length > 0 &&
object[eachIdx][0].constructor === Array
) {
object[eachIdx] = new Map(object[eachIdx]);
jsonstringToObject(object);
} else if (typeof object[eachIdx] == 'object')
jsonstringToObject(object[eachIdx]);
}

return object;
};

console.log(`-------------변환후`);
const result = jsonstringToObject(object);

console.log(result);

return result;
};
실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const myObject: MyType = {
id: 30,
cover: 'cover',
outComes: new Map([
[0, 'o1'],
[1, 'o2'],
]),
questions: new Map([
[
0,
new Map([
[1, 'answer1'],
[2, 'ansewr2'],
]),
],
[
1,
new Map([
[1, 'ansewr1'],
[2, 'ansewr2'],
]),
],
[2, new Map([])],
]),
};

console.log(`-----------------map을 포함한 오브젝트 json stringify`);
const rst = stringify(myObject);
console.log(rst);
console.log(typeof rst);

console.log(`-----------------다시 오브젝트화`);
const result = jsonString2ObjectWithMap<MyType>(rst);
output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
-----------------map을 포함한 오브젝트 json stringify
{
"id": 30,
"cover": "cover",
"outComes": [
[
0,
"o1"
],
[
1,
"o2"
]
],
"questions": [
[
0,
[
[
1,
"answer1"
],
[
2,
"ansewr2"
]
]
],
[
1,
[
[
1,
"ansewr1"
],
[
2,
"ansewr2"
]
]
],
[
2,
[]
]
]
}
string
-----------------다시 오브젝트화
-------------변환전
{
id: 30,
cover: 'cover',
outComes: [ [ 0, 'o1' ], [ 1, 'o2' ] ],
questions: [ [ 0, [Array] ], [ 1, [Array] ], [ 2, [] ] ]
}
-------------변환후
{
id: 30,
cover: 'cover',
outComes: Map { 0 => 'o1', 1 => 'o2' },
questions: Map { 0 => [ [Array], [Array] ], 1 => [ [Array], [Array] ], 2 => [] }
}

상황

  • 서버로 json 형태로 값을 전달하고 싶은데…
  • Map은 json stringify로 변환되지 않는다
  • 변환하기 위해서는 한번 Array로 변환한 다음에야 가능했다
  • 어떤 객체에 맵이 중첩으로 사용된 경우 수동으로 바꿔주는 게 귀찮다

해결

stringify.ts
1
2
3
4
5
6
7
8
9
const stringify = (object: any) => {
for (const eachIdx in object) {
if (object[eachIdx] instanceof Map) {
object[eachIdx] = Array.from(object[eachIdx]);
stringify(object);
} else if (typeof object[eachIdx] == 'object') stringify(object[eachIdx]);
}
return JSON.stringify(object, null, 2);
};
  • 객체 안 멤버들을 하나씩 돌아가면서 Map이거나 오브젝트인지 확인한다
  • Map이면은 JSON stringify 할 수 있는 Array로 변환한다
  • 오브젝트이면 중첩되어있는 Map을 찾기 위해 재귀적으로 반복한다

사용법

  • myObject와 같은 중첩 map을 포함하고 있고,
  • 포함되어있는 Map이 Map<number,string> 일 경우에만 때만 테스트해보아서, 더 다양한 경우에도 동작할지는 모르겠다
  • input : { a:… } 처럼 오브젝트를 넣어야 한다
  • console.log 찍어봤을 때 { }로 묶여있는…
  • 만약에 그냥 Map인 경우에는 이런 식으로 { a: new Map() } 한번 감싸주면 된다

repo

JSON.stringify 예쁘게 출력하기

1
JSON.stringify(my, null, 2);
  • 두번째 인자로 null
  • 세번째 인자로 space argument 를 설정해주면된다
  • space argument 는 들여쓰기를 간격에 대한 것이다

TMI

비교해보기

example
1
2
3
4
5
6
7
8
9
10
11
let my = {
key: 'a',
altKey: false,
code: 'KeyA',
ctrlKey: false,
keyCode: 65,
shiftKey: false,
};

console.log(JSON.stringify(my));
console.log(JSON.stringify(my, null, 2));
  • F12 로 개발자도구를 열고, 콘솔에 복붙해보자

html로 출력하고싶을 때

example.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<pre><code id="message"></code></pre>

<script>
'use strict';

const message_span = document.querySelector('#message');

let my = {
key: 'a',
altKey: false,
code: 'KeyA',
ctrlKey: false,
keyCode: 65,
shiftKey: false,
};

message_span.innerHTML = JSON.stringify(my, null, 2);
</script>
  • 로그로 남기는 것이 아니라 html로 그 결과를 보여주고 싶을 때에는
  • 위처럼 pre태그 안에서 보여주면된다

참고

typescript json import

tsconfig.json
1
2
3
4
5
6
{
"compilerOptions": {
// (...)
"resolveJsonModule": true
}
}
  • tsconfig.jsoncompilerOptions 부분에 resolveJsonModule를 추가한다
ex.ts
1
import myJsonData from './myJson.json';
  • 이런식으로 가져다 쓸 수 있다

참고