JSONについていつもわからなくなるのでまとめてみた

# はじめに
JSON（JavaScript Object Notation）は、現代のウェブ開発におけるデータ交換のデファクトスタンダードです。webアプリやモバイルアプリを問わず、開発ではJSONを扱う場面が少なからずあります。
しかし、そのたびに`JSON.stringfy`や`JSOM.parse`といった処理の関係性についてわからなくなり、ググったりコンソールに出して確認していたりしませんか？私はそうでした。
ですので今回は、私のような人がJSONを調べずに実装できるようになるためのまとめを書いてみたいと思います。

# いきなりクイズです。
次の2つのデータ形式のうち、どちらがJSONでしょうか？
形式A
```
{
  'name': 'Alice',
  'age': 25,
  'isStudent': true,
}

```
形式B
```
{
  "name": "Alice",
  "age": 25,
  "isStudent": true
}
```
正解はBです。
Aは一見JSONのように見えますが、シングルクォートを使用していることと、トレイリングカンマを使用しているため正しいJSON形式ではありません。JSONでは、すべてのキーと文字列値はダブルクォートで囲む必要があります。また、最後のフィールドにカンマをつけることもできません。
JSONは単なるデータフォーマットですが、JavaScriptのオブジェクトリテラル表記をベースにしているため、形式Aのような勘違いがよく起こります。
```
{
  'name': 'Alice', ← シングルクォートはダメ
  'age': 25,
  'isStudent': true, ← トレイリングカンマもダメ
}
```

# TypeScriptでのJSONの扱い方
TypeScriptでは、JSONデータを効率的に扱うために型を定義することができます。例えば、以下のような形でデータを表現を考えてみます。
```person.json
{
  "name": "John",
  "age": 30,
  "isStudent": false,
  "courses": ["Math", "Science"],
  "address": {
    "city": "New York",
    "zipCode": "10001"
  }
}
```
このようなJSONをTypeScriptで表現するには、次のように型を定義します。
```person.ts
type Address = {
  city: string;
  zipCode: string;
}

type Person = {
  name: string;
  age: number;
  isStudent: boolean;
  courses: string[];
  address: Address;
}

const person: Person = {
  name: "John",
  age: 30,
  isStudent: false,
  courses: ["Math", "Science"],
  address: {
    city: "New York",
    zipCode: "10001"
  }
};

```
### JSONをTypeScriptで型安全に扱う方法
上記のように型を定義することで、TypeScript内でJSONデータを扱う際に型の恩恵を受けることができます。しかし、JSONデータを外部から取り込む場合（例えばAPIレスポンスやファイル読み込み）には注意が必要です。

通常、以下のようにJSON.parseを使ってJSON文字列をパースしますが、これだけでは型安全性を担保できません。

```javascript
const jsonString = '{ "name": "John" }';
const parsedObject: Person = JSON.parse(jsonString); // これは型エラーを発生させないが、ランタイムエラーの原因になる可能性があります。
console.log(`年齢：${parsedObject.age}歳`); // ageがundefinedの場合、エラーが発生します。
```
このような場合、ランタイムエラーを防ぐために、zodやjson-type-validationなどのライブラリを使ってJSONデータを検証するのが良いでしょう。以下はzodを使った例です。

```javascript
import { z } from 'zod';

const PersonSchema = z.object({
  name: z.string(),
  age: z.number(),
  isStudent: z.boolean(),
  courses: z.array(z.string()),
  address: z.object({
    city: z.string(),
    zipCode: z.string()
  })
});

const jsonString = '{ "name": "John" }';

try {
  const parsedObject = PersonSchema.parse(JSON.parse(jsonString));
  console.log(`年齢：${parsedObject.age}歳`);
} catch (e) {
  console.error('Invalid JSON data:', e.errors);
}
```
このようにすることで、JSONデータが期待される型に合致しているかどうかを検証し、型安全に扱うことができます。

# JSON.stringify() と JSON.parse()
JavaScriptでJSONを扱う際に頻繁に使用する関数が JSON.stringify() と JSON.parse() です。
JSON.stringify() はJavaScriptのオブジェクトをJSON文字列に変換します。例えば：
```javascript
const jsonString = JSON.stringify(person);
console.log(jsonString);
// {
//   "name": "John",
//   "age": 30,
//   "isStudent": false,
//   "courses": ["Math", "Science"],
//   "address": { "city": "New York", "zipCode": "10001" }
// }
```
一方、JSON.parse() はJSON文字列をJavaScriptのオブジェクトに変換します。
```javascript
const parsedObject = JSON.parse(jsonString);
console.log(parsedObject);
// {
//   name: "John",
//   age: 30,
//   isStudent: false,
//   courses: Array(2),
//   address: {…}
// }
```
これらの関数を使えば、サーバーとクライアント間のデータ交換が非常に簡単になります。

## 意外と知らない便利な機能
JSONには、意外と知られていない便利な機能があります。その一つが、リプレイサー関数とスペース引数です。
スペース引数は出力する JSON 文字列に可読性を目的に空白 (インデントや改行など) を挿入するための機能です。
stringifyメソッドの第3引数に整形する際のインデントやタブを指定します。
```javascript
// 2文字分のインデントを挿入
const jsonString = JSON.stringify(person,null,2);
console.log(jsonString);
// {
//   "name": "John",
//   "age": 30,
//   "isStudent": false,
//   "courses": [
//     "Math", 
//     "Science"
//   ],
//   "address": { 
//     "city": "New York", 
//     "zipCode": "10001" 
//   }
// }
```
このようにすることで、JSON文字列を整形して表示することで開発時のデバックなどで役に立ちます。

また、リプレイサー関数を使うと、特定のプロパティだけをフィルタリングしたり、値を変換したりすることができます。
```javascript
const jsonString = JSON.stringify(person, (key, value) => {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value;
}, 2);
console.log(jsonString);
// {
//   "name": "JOHN",
//   "age": 30,
//   "isStudent": false,
//   "courses": [
//     "MATH", 
//     "SCIENCE"
//   ],
//   "address": { 
//     "city": "NEW YORK", 
//     "zipCode": "10001" 
//   }
// }
```

# 終わりに
JSONは非常にシンプルでありながら、強力なデータフォーマットです。今回紹介した基本的な使い方から、便利な機能まで、少しでもJSONに対する理解が深まれば幸いです。JSONをもっと深く理解し、活用してみてください。