4歳娘「パパ、オブジェクトから型を作って？」

## ある休日
娘（**4歳**）「パパ、ジャンケンしよ！？」

ワイ「おお、娘ちゃん」
ワイ「もうジャンケンができるようになったんか！」
ワイ「まだ**関数を書くこと**くらいしかできんと思ってたわ〜」

よめ太郎「順番どうなってんねん」

ワイ「ほな、ジャンケンしようや！」

## さっそく

娘「じゃあ、さっそく**コードを見ていきたいんだけど**・・・」

ワイ「**ファッ！？**」
ワイ「**コード！？**」

```ts:janken.ts
const hands = {
  gu: "グー",
  choki: "チョキ",
  pa: "パー"
};
```

娘「まず↑こんなオブジェクトを定義してみたの」

ワイ「お、おお」
ワイ「ジャンケンの手やから`hands`ね」

娘「そう」
娘「それで」
娘「この`hands`っていうオブジェクトから、**型**を作りたいの」

ワイ「オブジェクトから、型を、作る・・・？」

娘「`"グー"`か`"チョキ"`か`"パー"`っていう文字列しか許可しない・・・」
娘「`Hand`型っていうのを定義したいの」

ワイ「なるほどな」
ワイ「それなら・・・」

```ts:janken.ts
type Hand = "グー" | "チョキ" | "パー";
```

ワイ「↑これでええやん」
ワイ「この**Hand型**は`"グー"`か`"チョキ"`か`"パー"`っていう文字列しか許可せえへんで！」
ワイ「**union型**いうやつやな」
ワイ「これで、間違って**不正な値**を代入せんようにできるで！」
ワイ「試しに`"ピャー"`という文字列を代入しようとすると・・・」

<img width="299" alt="スクリーンショット 2020-06-04 22.05.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/faa75cfe-e894-6486-8e43-50c7fb39410d.png">

ワイ「ほら、VSCodeくんが赤い波線を表示してくれとる」
ワイ「エラーっちゅうことや」

娘「うん」
娘「でも、それは自分でunion型を書いてるだけでしょ？」
娘「`hands`っていうオブジェクトを元に、自動で**union型を作りたいの**」
娘「このオブジェクトの持つ値は`"グー"`か`"チョキ"`か`"パー"`って分かり切ってるのに」
娘「わざわざ自分で`"グー" | "チョキ" | "パー"`っていうunion型を再定義したくないの」

ワイ「ハハハ」
ワイ「それは、残念ながら無理なご相談や」
ワイ「それに、オブジェクトの中身が**書き換えられる可能性**もあるやん」
ワイ「いくら`const`で定義しても、オブジェクトは**不変ではない**んやから」

娘「でも前に、ハスケル子おねえちゃんが**できるって言ってたよ**」
娘「**オブジェクトからunion型を生成できる**って」

ワイ「（ぐぬぬ）」
ワイ「ええと・・・」

娘「パパ、早く教えて？」
娘「私の**稼働**がもったいないの」

ワイ「稼働て・・・」
ワイ「（なんか、ワイも前にハスケル子ちゃんから教えてもらった気がするな・・・）」

## 必死に思い出す
ワイ「せや！」
ワイ「確か、順序としては・・・」

1. まず**key**名から`"gu" | "choki" | "pa"`という**union型**を作る。
2. それを使って`"グー" | "チョキ" | "パー"`という**union型**を作る。

ワイ「↑こんな感じのはずや」
ワイ「あと・・・」

- keyof演算子
- typeof演算子

ワイ「↑この2つの演算子を使う、って言ってた気がするで」
ワイ「あと、まずは」
ワイ「`hands`オブジェクトの**最後んところ**に`as const`をつけるんや」

```ts:janken.ts
const hands = {
  gu: "グー",
  choki: "チョキ",
  pa: "パー"
} as const; // <- 追加
```

ワイ「↑こうやな」
ワイ「これで`hands`オブジェクトは、中身を書き換えたりできない・・・」
ワイ「**readonly**なオブジェクトになったんや」

娘「へぇ〜」

ワイ「このオブジェクトの持つ値は`"グー"`か`"チョキ"`か`"パー"`だって、確定してないとアカンからな」

娘「なるほどね」

ワイ「試しに**VSCode**で`hands`オブジェクトにマウスを乗せて」
ワイ「`hands`オブジェクトの**型を確認**してみ？」

娘「うん！」

<img width="337" alt="スクリーンショット 2020-06-04 22.03.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/6301ed6f-35bd-7dce-a016-63a2b2d63413.png">


娘「ほんとだ！」
娘「全部のkeyが**readonly**になってる！」

ワイ「これで、`hands`オブジェクトの**key**は常に`gu`、`choki`、`pa`であること」
ワイ「**value**は常に`"グー"`、`"チョキ"`、`"パー"`であること」
ワイ「それが**型によって担保**されたで！」
ワイ「ほんまの意味で**定数**になったってことやな」

娘「だから`as const`なんだね！」

## typeofで型情報を見る

娘「パパ、それで」
娘「まず**key**名から`"gu" | "choki" | "pa"`っていう**union型**を作るんだっけ？」
娘「どうやってやるの？」

ワイ「まずな、`hands`オブジェクトの型情報があったやろ？」

娘「さっきVSCodeで確認したやつね」

ワイ「せや」
ワイ「それに別名を付けてやるんや」

```ts:janken.ts
type Hoge = typeof hands;
```

ワイ「↑こうや」

娘「へぇ〜」
娘「`typeof hands`っていうのが」
娘「`hands`オブジェクトの型情報、ってことなんだ！」
娘「それに`Hoge`っていう別名を付けたんだね」

ワイ「せや」
ワイ「またVSCodeでマウスを乗せて確認してみ？」
ワイ「`Hoge`型に何が入っとるかを見るんや」

娘「うん！」

<img width="337" alt="スクリーンショット 2020-06-04 22.03.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/f3917516-81c2-3ac0-f165-4dea818d4d83.png">


娘「ほんとだ」
娘「さっきの`hands`オブジェクトの型情報と同じだ」

ワイ「そういう感じや」

## keyofで、key名からunion型を定義する

ワイ「次は`keyof`を使って」
ワイ「`Hoge`型に存在する**key名**から**union型を作る**んや」

```ts:janken.ts
type Keys = keyof Hoge;
```

ワイ「↑こうやな」
ワイ「マウスを乗せて`Keys`型の中身を見てみ？」

<img width="365" alt="スクリーンショット 2020-06-04 22.03.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/1186d6c5-6b9a-89f3-5c1b-1a86b0df4c29.png">

娘「あ、`"gu" | "choki" | "pa"`っていうunion型が出来てる」

ワイ「せや」
ワイ「こいつを元に、最終目的である・・・」
ワイ「`"グー" | "チョキ" | "パー"`という**union型**を作るんや！」

娘「おお〜」
娘「今日のパパ、なんか凄い！」

## またtypeofで型情報を見る

ワイ「次にやることは↓こんなイメージや」

```ts:janken.ts
type Hand = typeof hands["gu"];
```

娘「`typeof`で`hands["gu"]`の型を見て」
娘「その型に`Hand`っていう別名を付けたんだね」

ワイ「せや」
ワイ「この`Hand`型の中身は何やと思う？」

娘「ええと」


```ts:janken.ts
const hands = {
  gu: "グー",
  choki: "チョキ",
  pa: "パー"
} as const;
```

娘「まず、`hands`オブジェクトの中身は↑こうだから」
娘「`hands["gu"]`の中身は`"グー"`でしょ？」
娘「だから、要は`typeof "グー"`は何になるか、的な話でしょ？」
娘「じゃあ、型もそのまま`"グー"`なんじゃない？」

ワイ「正解や」

娘「念のためマウス乗せて見てみよ」

<img width="293" alt="スクリーンショット 2020-06-04 22.04.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/edf2f8d5-3675-9a66-427b-94319ab36b1a.png">

娘「ほんとだ。`Hand`型の中身は`"グー"`だ」

ワイ「せやせや」
ワイ「ほな、これはどうや？」

```ts:janken.ts
type Hand = typeof hands["gu" | "choki"];
```

娘「ええと」
娘「`hands["gu" | "choki"]`だから」
娘「値としては`"グー"`か`"チョキ"`が入ってる**イメージ**だよね」
娘「じゃあ、型は`"グー" | "チョキ"`かな？」

ワイ「さすが、正解や」

<img width="396" alt="スクリーンショット 2020-06-04 22.26.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/bdb065a3-a9cc-34a4-8214-2b3664c3be1b.png">

娘「ほんとだ」
娘「ってことは・・・」

```ts:janken.ts
type Hand = typeof hands["gu" | "choki" | "pa"];
```

娘「↑こうすれば・・・」
娘「`"グー" | "チョキ" | "パー"`っていう**union型**が作れるんだね！？」
娘「私の欲しかったやつ！」

ワイ「せや！」

娘「さっき**keyof**で作った`Keys`型が」
娘「`"gu" | "choki" | "pa"`っていうunion型だったから」
娘「それを使うんだね！」

ワイ「せや」

娘「つまり・・・」

```ts:janken.ts
type Hand = typeof hands[Keys];
```

娘「↑こうだね！？」

ワイ「さぁ〜、どうやろね」

娘「VSCodeでマウスを乗せて覗いてみる！」

<img width="380" alt="スクリーンショット 2020-06-04 22.04.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/177c5c08-f8fe-d1e3-94a4-8b46cdb7092c.png">

娘「できた！」
娘「`hands`オブジェクトから`Hand`型ができた！」
娘「これで、分かり切った`"グー" | "チョキ" | "パー"`を書かなくても」
娘「オブジェクトの値から、自動っぽく型が作れる！」
娘「パパ、ありがとう！」

ワイ「グヘヘ」

娘「試しに不正な値を代入してみよっと！」

<img width="299" alt="スクリーンショット 2020-06-04 22.05.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/faa75cfe-e894-6486-8e43-50c7fb39410d.png">

娘「あ、ちゃんとエラー扱いになって、波線が表示されてる！」
娘「これで、`Hand`型の変数には」
娘「`"グー"`か`"チョキ"`か`"パー"`しか代入できないね！」
娘「不正な値は代入できないね！」

ワイ「せや！」
ワイ「ちなみに、いちいち型エイリアスを作らなくても」

```ts:janken.ts
type Hand = typeof hands[keyof typeof hands];
```

ワイ「↑こう書いても同じことやで」
ワイ「確認のためにVSCodeで見てみると・・・」

<img width="418" alt="スクリーンショット 2020-06-04 22.43.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/5b023f2b-9deb-b4c4-8017-61e252ab5920.png">

ワイ「↑ほらな」

娘「ほんとだ！」

ワイ「せやから、全体のコードとしては・・・」

```ts:janken.ts
const hands = {
  gu: "グー",
  choki: "チョキ",
  pa: "パー"
} as const;

type Hand = typeof hands[keyof typeof hands];
```

ワイ「↑これだけや」

娘「オブジェクトを元にして型を定義する部分は」
娘「1行で書けちゃうんだね」

ワイ「せやで」

## 反復処理も可能

ワイ「元となるオブジェクトである`hands`が存在してる訳やから」
ワイ「`Object.keys(hands)`とか`Object.values(hands)`とか`Object.entries(hands)`みたいな」
ワイ「反復処理も可能やで！」

娘「いいね！」
娘「たまにそういうことしたい時あるもんね！」

よめ太郎「**４歳児には無いやろ**」

## でも、enumでよくない？

娘「でもさ・・・」
娘「これ**enum**で良くない？」

```ts:janken.ts
enum Hands {
  gu = "グー",
  choki = "チョキ",
  pa = "パー"
}
```

娘「↑こんな感じで良くない？」
娘「[**enumでも反復処理はできる**](https://qiita.com/wildmouse/items/96ec2a5892e88ea4aec6)みたいだし」

ワイ「enumでもええねんけど」
ワイ「enumって何か、分かりにくいやん」

娘「そう？」

ワイ「enumという**型**に対して`Object.entries()`とかそういう」
ワイ「**オブジェクト用のメソッド**が適用できるのが何か腑に落ちんし」
ワイ「TSからJSに変換されると**訳わからんコード**になってまうし」
ワイ「人類には早過ぎたんや」

よめ太郎「人類っていうかお前個人の問題やな」

娘「でもまあ、分からなくもないね」

## まとめ

+ typeof演算子を使うと、**型の情報を取得**して別名をつけることができた。
+ keyof演算子を使うと、型の**key名**から**union型を生成**できた。
+ `typeof obj[keyof typeof obj]`とする事で、オブジェクトから**union型を生成**できた。
+ 元となるオブジェクトが存在するため、`Object.keys()`や`Object.values()`や`Object.entries()`などの反復処理も可能。

娘「↑こんな感じだね！」

ワイ「せや！」

## その日の夜

ワイ「はあ、今日は娘ちゃんの役に立てて嬉しいわ」
ワイ「ワイでも技術的なことで役に立てることがあるんやな」
ワイ「滅多にないけどな」
ワイ「・・・せや！」
ワイ「もう一回さっきのコードいじって復習しとこ」

```ts:janken.ts
type Hand = typeof hands["guu"];
```

ワイ「↑こう書くと、確か・・・」
ワイ「`Hand`型の中身は`"グー"`になるはずやったな」
ワイ「VSCodeで確認してみよ」

<img width="365" alt="スクリーンショット 2020-06-06 23.53.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295452/31195bff-c5fc-ce43-fcf5-70132e3cf990.png">

ワイ「**ファッ！？**」
ワイ「**アニー**になっとるやないかい！」

よめ太郎「**エニー**や」
よめ太郎「**アニー**てそれ、ミュージカルやないかい」
よめ太郎「**♪トゥモロー、トゥモロー**言うてる場合か」

ワイ「そ、それより何で、型が**`any`**に・・・」
ワイ「・・・分かった！」
ワイ「**VSCodeのバグや！**」

よめ太郎「**バグってんのはお前の脳みそや**」

ワイ「いや、これはワイが正しい気がする」

よめ太郎「**タイポしてんねん**」
よめ太郎「`"gu"`を`"guu"`ってミスタイプしてんねん」

ワイ「**ファッ！？**」

よめ太郎「お前のは**TypeScript**やなくて**タイポスクリプト**や」

ワイ「ぐぬぬ」

よめ太郎「VSCodeはな」
よめ太郎「TypeScriptを作っとる**Microsoft**はんが作ってんねや」
よめ太郎「**何でお前の方が正しいと思えたねん**」

ワイ「テヘヘ・・・」
ワイ「**ジョブズ**に怒られてまうわ」

よめ太郎「Microsoftは**ビル・ゲイツ**やろ・・・」
よめ太郎「エグいほど無知やな・・・」

ワイ「ぐぬぬ」
ワイ「いや・・・ワイはジョブズの方が好きやから・・・なんか・・・間違えてもうたわ」

よめ太郎「言い訳が苦し過ぎやろ」

ワイ「い、言い訳ちゃうわ」
ワイ「ほ、ほんまにジョブズが好きなんやワイは！」

よめ太郎「そうか」
よめ太郎「**ほな、今から会わせたるわ・・・**」

**〜おしまい〜**

## 参考文献

- [**型の移動 - TypeScript Deep Dive 日本語版**](https://typescript-jp.gitbook.io/deep-dive/type-system/moving-types)
- [**さようなら、TypeScript enum**](https://www.kabuku.co.jp/developers/good-bye-typescript-enum)