5歳娘「パパ、型はドキュメントだよ？」

## とある休日

娘（**5歳**）「パパ、今日はお休みだから一緒にゲームしよ？」

ワイ「ええで！なんのゲームする？」
ワイ「スーパー正男ブラザーズでもやろか？」

娘「ううん」
娘「**コードジャンケン**しよ！」

ワイ「なんや、その恐ろしそうな名前のゲームは。。。」

娘「なんか仕様を決めて、**どっちが読みやすいコードで実装できるか**勝負するの！」

ワイ「おお、ええで」
ワイ「流石に5歳児には負けへんで！」
ワイ「**6歳児だと危うい**けどな！」

娘「じゃあ、ママ」
娘「何か仕様をちょうだい！」

よめ太郎「ええで」

## 仕様: 数値を文字列に変換する

よめ太郎「仕様、考えたで」
よめ太郎「**数値**を**文字列**に変換する、っちゅう内容や！」

> ### 【いま考えた仕様書】
>
> - とあるAPIから`0〜2`の数値が返ってくるとする
> - `0〜2`の数値は、**ユーザーの申込進捗状況**を表しているものとする
> - `0〜2`の数値は、それぞれ以下の状態を表している
>   - `0` → 申込書到着
>   - `1` → 申込手続中
>   - `2` → 申込完了
> - 画面上では、数値ではなく**文字列として表示する必要がある**。
>
> 上記の数値を、画面表示用の文字列に変換する処理を実装せよ。

ワイ「ほう・・・**ユーザーの申込進捗状況**ねぇ」
ワイ「要するに・・・」
ワイ「APIから`0`が返ってきたら、画面には`'申込書到着'`って表示する」
ワイ「APIから`1`が返ってきたら、画面には`'申込手続中'`って表示する」
ワイ「APIから`2`が返ってきたら、画面には`'申込完了'`って表示する」
ワイ「そのための、**数値から文字列への変換処理**を書けってことやな？」

よめ太郎「そういうことや」

ワイ「クッソ簡単やん」
ワイ「こんなん、誰が書いても同じやろ」

娘「言語は**TypeScript**でいい？」

ワイ「ええで！」
ワイ「ほな勝負や！」

## ワイのコード

ワイ「書けたで！」

```typescript:wai.ts
const userStatuses: Array<string> = [
    '申込書到着',
    '申込手続中',
    '申込完了'
]
```

ワイ「↑こうや！」

よめ太郎「なるほどな」
よめ太郎「数値は`0`か`1`か`2`な訳やから」
よめ太郎「配列を用意しておいて、その数値でアクセスすればいいって訳か」

ワイ「せや」

```typescript:wai.ts
console.log(userStatuses[0])
// -> '申込書到着'

console.log(userStatuses[1])
// -> '申込手続中'

console.log(userStatuses[2])
// -> '申込完了'
```

ワイ「↑こんな感じや！」

よめ太郎「なるほどな、シンプルやな」

## 5歳娘ちゃんのコード

娘「私も書けたよ！」

```typescript:musume.ts
type ApiValue = 0 | 1 | 2
type DisplayText = string

const userStatusTextMap: Map<ApiValue, DisplayText> =
    new Map([
        [0, '申込書到着'],
        [1, '申込手続中'],
        [2, '申込完了']
    ])
```

娘「↑こんな感じ！」

よめ太郎「ほうほう」
よめ太郎「まずは・・・」

```typescript:musume.ts
type ApiValue = 0 | 1 | 2
```

よめ太郎「なるほど」

> 型「APIから返ってくる値は、`0`か`1`か`2`のどれかやで！」

よめ太郎「↑ってことを表しているんやな」

娘「うん！」

よめ太郎「**説明的**でええやないか」
よめ太郎「ほんで、次の行は・・・」

```typescript:musume.ts
type DisplayText = string
```

よめ太郎「`string`型に、**別名**を付けてあげてる訳か」

娘「うん！」

> 型「ここでの`string`は、**画面に表示するための文字列**ですよ！」

娘「ってことを表現してみたの」

よめ太郎「ああー」
よめ太郎「単に`string`だと、**なんのための文字列なのか**ってことまでは分からへんもんな」
よめ太郎「せやから、もう少し**意味のある型名**を付けてあげた訳やな」
よめ太郎「素敵やん」
よめ太郎「そんで、その次は・・・」

```typescript:musume.ts
const userStatusTextMap: Map<ApiValue, DisplayText> =
    new Map([
        [0, '申込書到着'],
        [1, '申込手続中'],
        [2, '申込完了']
    ])
```

よめ太郎「なるほどな」
よめ太郎「この・・・」

```typescript:musume.ts
Map<ApiValue, DisplayText>
```

よめ太郎「っていう型がエエ感じやな」

> 型「**APIから取得した値**と**表示用テキスト**の**対応表**ですよ！」

よめ太郎「↑こんな感じが滲み出てるな」

ワイ「ああ〜、そうか」
ワイ「**Map**って**対応表**って意味やもんな」

娘「うん」
娘「それで、こんな感じで使うの」

```typescript:musume.ts
console.log(userStatusTextMap.get(0))
// -> '申込書到着'

console.log(userStatusTextMap.get(1))
// -> '申込手続中'

console.log(userStatusTextMap.get(2))
// -> '申込完了'

console.log(userStatusTextMap.get(3))
// -> コンパイルエラー！！！
```

よめ太郎「おお〜」
よめ太郎「`ApiValue`の値を`0`か`1`か`2`に制限してあるから」
よめ太郎「`3`のぶんを取得しようとすると、ちゃんとコンパイルエラーが起きるんやな」
よめ太郎「ええやん」

娘「てへへ」

よめ太郎「こういうのも、**型の旨み**やもんな」

## 勝敗判定中

よめ太郎「娘ちゃんのコードは、全体的に**説明的**で良いな」
よめ太郎「コードを読んだだけでも・・・」

> 「こんな仕様書だったんやろな〜」

よめ太郎「っていうことが、なんとなく想像できるわ」
よめ太郎「このコードを**後から保守する人**も・・・」

> 保守担当「むむ？」
> 保守担当「`Map<ApiValue, DisplayText>`とな？」
> 保守担当「なるほど、これは・・・」
> 保守担当「**APIから取得した値**と**表示用テキスト**の**対応表**ってことか」

よめ太郎「って感じで、**型の意図**を読み取りやすそうやな」
よめ太郎「**修正フェーズ**や**保守フェーズ**で価値を発揮しそうなコードやな」

娘「うん、そこは意識してみたよ」
娘「この部分のコードだけ読んでも、できるだけ意味や意図が分かるように、って」

よめ太郎「なるほどな」

娘「小さなプロジェクトなら、仕様書を全部読んで、コードも型も全部読んで」
娘「全部理解してから修正すればいいけど」
娘「大規模な案件だと、全ての仕様を理解して、全体のコードを読んでから修正するとか」
娘「頭がパンクしちゃうもん」

よめ太郎「まあ、できれば全体を把握した方がええんやろうけど」
よめ太郎「一部分だけを見ても分かりやすい、説明的な型やコードが書かれてると」
よめ太郎「あとから読む人は、すごく助かるよな！」

娘「そうだね！」
娘「**型は、ドキュメントの役割もする**からね！」

ワイ「（型はドキュメント・・・？）」
ワイ「（何を言うてんの・・・？）」
ワイ「（でも・・・）」
ワイ「**せやな！型はドキュメントや！**」
ワイ「（一応言うとこ・・・！）」

よめ太郎「かたや、やめ太郎のコードは・・・」

```typescript:wai.ts
const userStatuses: Array<string> = [
    '申込書到着',
    '申込手続中',
    '申込完了'
]
```

ワイ「う〜ん、まさに」
> 型「**APIから取得した値**と**表示用テキスト**の**対応表**ですよ！」

ワイ「って、型が**語りかけてきてる**感じがするな！」

よめ太郎「**いやどこがやねん**」
よめ太郎「どこから感じたねん」
よめ太郎「エスパーか」

ワイ「ぐぬぬ・・・」

よめ太郎「`Array<string>`という型から分かるんは」

> 型「文字列が入った配列やで」

よめ太郎「それだけやろ」

ワイ「確かに・・・」

## 結果発表

よめ太郎「ほな、結果発表するで」

ワイ「ワクワク・・・！」

よめ太郎「ようワクワクできるな」

ワイ「ぐぬぬ」

よめ太郎「勝者は・・・」
よめ太郎「**娘ちゃんや！**」

ワイ「まぁ、知ってたわ・・・」

よめ太郎「せやろな」
よめ太郎「勝因としては・・・」

- **型や命名**で、できる限り**仕様を説明**していた

よめ太郎「ってとこやな」

ワイ「なるほどな・・・」
ワイ「**型はドキュメント**・・・」
ワイ「そういうことか・・・」

よめ太郎「しかも、型で書いた通りに実装せんと」
よめ太郎「エラーが出て前に進めない・・・」
よめ太郎「**強制力のあるドキュメント**やな」

ワイ「確かに」
ワイ「コメントはワンチャン間違っとるかもしれんけど」
ワイ「型は、間違っとったらコンパイルエラーで進めへんもんな」

よめ太郎「せや」
よめ太郎「テストコードと並んで、一番信頼できるドキュメントと言えるかもしれん」

## まとめ

- 型の付け方で**仕様を説明**できると素敵やね
- 元々ある型に**別名を付けて説明**してあげるのもええね
- 型はドキュメント的な役割も果たすんやね

ワイ「↑こういうことやな！」
ワイ「これで、さらにコメントもちゃんと書けば」
ワイ「だいぶリーダブルなコードになりそうやな」

よめ太郎「せやな」
よめ太郎「あ！でも一点だけ・・・」

```typescript:musume.ts
Map<ApiValue, DisplayText>
```

よめ太郎「↑ここは」

```typescript:musume.ts
ReadonlyMap<ApiValue, DisplayText>
```

よめ太郎「↑こうの方がええかもな」

娘「あ、そっか」
娘「`ReadonlyMap`型のほうがよかったね」

よめ太郎「`ReadonlyMap`にしておけば、**上書きできひん**から・・・」

```typescript:musume.ts
userStatusTextMap.set(2, '死亡')

console.log(userStatusTextMap.get(2))
// -> '死亡'
```

よめ太郎「↑こういう事故が防げるもんな」

娘「そうだね」
娘「それに・・・」

> 型「上書きする必要のない、**読み取り専用の対応表**やで！」

娘「ってことも伝わるしね」
娘「あー、そうすればよかったなぁ」

ワイ「そうかぁ」
ワイ「ってことは・・・ワイの勝ちかな？」

よめ太郎「**いやちゃうやろ**」

**〜おしまい〜**