吾輩はバグを出す　〜Mapped typesでミス対策〜


## ある日、某システム会社にて

ワイ「カタカタカタカタ・・・」

ハスケル子「やめ太郎さん」
ハスケル子「さっきから一生懸命、何を書いてるんですか？」

ワイ「小説や」
ワイ「これで一発当てて、会社なんて辞めてやるんや・・・！」

ハスケル子「へえ〜、それは凄いですね（棒読み）」
ハスケル子「ちょっと読ませてくださいよ」

ワイ「ええで」

ハスケル子「ええと、タイトルは」
ハスケル子「・・・**吾輩はバグを出す**・・・？」
ハスケル子「なるほど」
ハスケル子「**ノンフィクション小説**ですね？」

ワイ「**どういう意味やねん**」
ワイ「フィクションや、フィクション」

## 仕事をしろ

ハスケル子「それよりやめ太郎さん」
ハスケル子「今日から新しい仕事が始まりますよ」
ハスケル子「**株式会社ジャンケンポン**さんの、コーポレートサイトを作るお仕事です」

ワイ「ああ、せやったな」
ワイ「どんなサイトを作るんやったっけ」
ワイ「仕様書を読んでみよか」

> - トップページで「ジャンケンゲーム」ができるようにして欲しい。

ワイ「なるほどな」
ワイ「社名にちなんで、って事やな」

ハスケル子「じゃあ、早速ペアプロしていきましょうか」

ワイ「せやな」

## ペアプロ開始

ワイ「ジャンケンと言えば、**グー・チョキ・パー**やな」
ワイ「ワイはよく、チョキを**チャカ**って打ち間違えてしまうから」
ワイ「それを防ぐために、ちゃんと型をつけておかんとな」

ハスケル子「そうですね」
ハスケル子「**チャカを出したらまずい**ですもんね」

ワイ「そういうことや」
ワイ「せやから・・・」

```typescript
type Hands = "グー" | "チョキ" | "パー";
```

ワイ「↑これでええな」
ワイ「これで、**Hands型**の変数には`"グー"`か`"チョキ"`か`"パー"`しか代入できひん」

```typescript
type Hands = "グー" | "チョキ" | "パー";

const hand: Hands = "チャカ"; // コンパイルエラー！
```

ワイ「↑こんな感じで」
ワイ「**チャカ**の混入を防げるってわけや」
ワイ「テキストエディタ上でも・・・」

![スクリーンショット 2020-09-15 22.29.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/8323c552-ca1d-f87e-672c-3cf0c1d7c4a1.png)


ワイ「↑こんな感じで、ちゃんと<font color="red">**赤い波線**</font>が表示されて」
ワイ「ミスに気付けるで」

ハスケル子「いいですね」

ワイ「やっぱ静的型付け言語ってええなぁ」
ワイ「ブラウザ上で実際にコードを動かす前に」
ワイ「テキストエディタでコードを書いてる段階でエラーに気づけるから、便利やな」

ハスケル子「そうですね」
ハスケル子「矛盾が生じるようなコードを書いてしまった時に」
ハスケル子「事前に気づけるから効率的ですよね」

ワイ「そうそう」

ハスケル子「間違えないように人間が気をつけてプログラミングをするより」
ハスケル子「間違えたらコンパイラが怒ってくれる方が良いですもんね」

ワイ「せやせや」

## ところが

ハスケル子「でもやめ太郎さん」
ハスケル子「このサイト、日本語だけじゃなくて」
ハスケル子「**英語での表示**もしないといけないみたいですよ」

ワイ「マジかいな」
ワイ「どれどれ、仕様書には何てかいてあんねん」


> - **英語での表示**もできること。
- 英語モードのときは「グー・チョキ・パー」を「Rock・Scissors・Paper」と表示すること。

ワイ「Oh...」
ワイ「どうすればええねん・・・」

## 閃いた

ワイ「分かったで」
ワイ「こういうオブジェクトを作ればええんや」

```typescript
// 日本語用
const handsJa = {
    gu: "グー",
    choki: "チョキ",
    pa: "パー",
};

// 英語用
const handsEn = {
    gu: "Rock",
    chaka: "Scissors",
    pa: "Paper",
};
```

ワイ「↑こうしておけば・・・」

```typescript
console.log(handsJa["gu"]); // グー

console.log(handsEn["gu"]); // Rock
```

ワイ「↑こんな感じで、`"gu"`という文字列を」
ワイ「日本語の`"グー"`に変換して表示したり」
ワイ「英語の`"Rock"`に変換して表示したりできるわけや」

ハスケル子「なるほど」
ハスケル子「**対応表**っぽいオブジェクトを作るわけですね」

ワイ「せや」
ワイ「基本的には`"gu"`・`"choki"`・`"pa"`という文字列を使って処理を行って」
ワイ「画面に表示するときだけは**対応表オブジェクト**を通して日本語や英語に変換する感じや」
ワイ「そうすれば、アルゴリズムの部分は日本語と英語を分けずに、共通化できるで！」

ハスケル子「良さげですね」
ハスケル子「でもやめ太郎さん」

```typescript
    chaka: "Scissors",
```

ハスケル子「↑さっそく**チャカが混入**してますよ」

ワイ「**ファッ！？**」
ワイ「`choki`を`chaka`って打ってもうたんか」

### ワイ「またチャカを打ってもうたぁ〜！！！」

ハスケル子「やめ太郎さん、**語弊がエグいです**」
ハスケル子「通報されますよ」

## プロパティ名をタイポしないために

ワイ「ワイはすぐタイポしてしまうなぁ」
ワイ「これじゃTypeScriptやなくて**タイポスクリプト**やで」
ワイ「・・・言うてる場合ちゃうわ」
ワイ「ほんま、気をつけんとなぁ・・・」

ハスケル子「やめ太郎さん」
ハスケル子「いつもそう言って」
ハスケル子「気をつけられた試しがないじゃないですか」

ワイ「ぐぬぬ」

ハスケル子「ここは**TypeScriptの力を頼りましょう**」

ワイ「と言いますと・・・」

ハスケル子「**Mapped types**を使いましょう」

## Mapped typesを使ってみる

ハスケル子「まずは・・・」

```typescript
type Hands = "gu" | "choki" | "pa";
```

ハスケル子「↑こうです」

ワイ「Hands型の変数には、`"gu"`か`"choki"`か`"pa"`しか代入できませんよ、ていう」
ワイ「そういう感じやな」

ハスケル子「はい」
ハスケル子「ここで**Mapped types**を使います」

```typescript
type HandsDisplay = {
    [P in Hands]: string
};
```

ハスケル子「↑こうです」

ワイ「え？」
ワイ「ワイはてっきり・・・」

```typescript
type HandsDisplay = {
    gu: string
    chaka: string
    pa: string
};
```

ワイ「↑こうかと思ってたわ」

ハスケル子「同じことですね」

ワイ「そうなんや」
ワイ「Hands型の値と対応したプロパティ名・・・」
ワイ「つまり`"gu"`・`"choki"`・`"pa"`というプロパティ名を持つ」
ワイ「そんなオブジェクト型を、サクッと書けるわけか」
ワイ「短く書けて便利やね」

ハスケル子「短いのも良いんですけど、それよりも」
ハスケル子「Hands型を元に、オブジェクトの型を**自動っぽく生成**できるのがメリットですね」

ワイ「ふーん」
ワイ「そこ自動化するくらいでメリットある？」

ハスケル子「あります」
ハスケル子「その証拠に、やめ太郎さんが手動で書いたHandsDisplay型には・・・」

```typescript
    chaka: string
```

ハスケル子「↑**チャカ**が混入しています」

ワイ「ぐぬぬ」

```typescript
type HandsDisplay = {
    [P in Hands]: string
};
```

ハスケル子「↑こうやって」
ハスケル子「Mapped typesを使って書けば」
ハスケル子「`gu`・`choki`・`pa`というプロパティを持つオブジェクト型を」
ハスケル子「確実に生成できます」
ハスケル子「仮に、Hands型の値が**数百種類**だったとしてもミスりません」
ハスケル子「`chaka`も混入しません」

![スクリーンショット 2020-09-15 22.28.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/fddd8b62-e492-3b5b-9142-81e2634b233e.png)

ハスケル子「ほら」
ハスケル子「ちゃんと`chaka`の部分にエラーが出てます」

ワイ「なるほどな」
ワイ「**ある型に対応した、オブジェクト型を定義する**・・・」
ワイ「Mapped typesを使うとそんなことができるんやな」

ハスケル子「そうですね」
ハスケル子「**map**という単語には」
ハスケル子「**対応づける**とか**対応表**って意味もありますからね」

ワイ「おお、**対応表**か」
ワイ「何かに対応したプロパティ名を持つオブジェクト型、って」
ワイ「割と作りたいときあるから」
ワイ「そんなときには**Mapped types**を使わしてもらうわ！」
ワイ「値の種類が多い場合なんか、特に便利やな！」

ハスケル子「Hands型の値の種類が**数百に増えた場合**にも」
ハスケル子「HandsDisplay型は**自動で追従**してくれますしね！」

ワイ「おお、良さげやな！」

社長「（ジャンケンの手、そんな増えへんやろ・・・）」
社長「（片手でどうやって表現すんねん・・・）」

## まとめ

ワイ「吾輩はバグを出す」
ワイ「知能はまだない」
ワイ「どこでバグらせたか、とんと見当がつかぬ」
ワイ「だから、TypeScriptを導入して」
ワイ「コンパイラに見つけてもらおう」

ハスケル子「そういうことですね」

**〜おしまい〜**