LoginSignup
465
269

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-06-07

ある休日

娘(4歳)「パパ、ジャンケンしよ!?」

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

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

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

さっそく

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

ワイ「ファッ!?
ワイ「コード!?

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

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

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

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

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

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

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

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

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

スクリーンショット 2020-06-04 22.05.10.png

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

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

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

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

ワイ「(ぐぬぬ)」
ワイ「ええと・・・」

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

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

必死に思い出す

ワイ「せや!」
ワイ「確か、順序としては・・・」

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

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

  • keyof演算子
  • typeof演算子

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

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

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

娘「へぇ〜」

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

娘「なるほどね」

ワイ「試しにVSCodehandsオブジェクトにマウスを乗せて」
ワイ「handsオブジェクトの型を確認してみ?」

娘「うん!」

スクリーンショット 2020-06-04 22.03.11.png

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

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

娘「だからas constなんだね!」

typeofで型情報を見る

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

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

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

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

janken.ts
type Hoge = typeof hands;

ワイ「↑こうや」

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

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

娘「うん!」

スクリーンショット 2020-06-04 22.03.26.png

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

ワイ「そういう感じや」

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

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

janken.ts
type Keys = keyof Hoge;

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

スクリーンショット 2020-06-04 22.03.38.png

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

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

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

またtypeofで型情報を見る

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

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

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

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

娘「ええと」

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

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

ワイ「正解や」

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

スクリーンショット 2020-06-04 22.04.08.png

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

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

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

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

ワイ「さすが、正解や」

スクリーンショット 2020-06-04 22.26.27.png

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

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

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

ワイ「せや!」

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

ワイ「せや」

娘「つまり・・・」

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

娘「↑こうだね!?」

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

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

スクリーンショット 2020-06-04 22.04.36.png

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

ワイ「グヘヘ」

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

スクリーンショット 2020-06-04 22.05.10.png

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

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

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

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

スクリーンショット 2020-06-04 22.43.43.png

ワイ「↑ほらな」

娘「ほんとだ!」

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

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)みたいな」
ワイ「反復処理も可能やで!」

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

よめ太郎「4歳児には無いやろ

でも、enumでよくない?

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

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

娘「↑こんな感じで良くない?」
娘「enumでも反復処理はできるみたいだし」

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

娘「そう?」

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

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

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

まとめ

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

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

ワイ「せや!」

その日の夜

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

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

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

スクリーンショット 2020-06-06 23.53.41.png

ワイ「ファッ!?
ワイ「アニーになっとるやないかい!」

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

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

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

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

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

ワイ「ファッ!?

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

ワイ「ぐぬぬ」

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

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

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

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

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

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

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

〜おしまい〜

参考文献

465
269
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
465
269