Web開発ログ | エンジニアに役立つ情報 | 開発の中での気づきを発信

高卒Devlog

TSLab【第8回 TypeScript勉強会】型の再利用と型パズル

thumbnail

こんにちは! RYOTAです!

当記事をご覧くださりありがとうございます!

当記事はTSLab勉強会(定例会)のレポート記事になります!

はじめに

私が運営しているTSLabの第8回TS定例会の実施ログとなります。
今回のテーマは「型の再利用と型パズル」です!

ディスカッション内容

インデックスアクセス

オブジェクト型に対してインデックスを指定することで、指定プロパティのvalueの型を取得します。
Type["property"] の形でアクセスすることが可能です。

type TestObject = { 
    a: number; 
    b: string; 
    c: boolean 
};

type TestA = TestObject["a"];
// type TestA = number

type TestB = TestObject["b"];
// type TestB = string

type TestC = TestObject["c"];
// type TestC = boolean

条件付き型 (継承判定)

今回初めて知ったのがこちら。
型定義時に、三項演算子で型を分岐できるらしい。(マジか。)
それに加え、条件にextendsを用いることで、継承関係をチェックして三項演算子で分岐できるよう。(マジか。)

interface A {
  a: string;
}

// B は A をextendsしたもの 
interface B extends A {
  b: number;
}

interface C {
  c: boolean;
}

// B は A からextendsされたものなので判定が true になる
type Test1 = B extends A ? number : string;
// type Test1 = number

// C は A からextendsされたものではないので判定が false になる
type Test2 = C extends A ? number : string;
// type Test2 = string

TypeScriptは表現の幅が広くて本当に凄いですね。
ただ、こちらは実際のユースケースが想像できないので、"こんなケースで使えるよ"等がございましたら是非教えていただけると助かります。

条件付き型 (プロパティ判定)

ジェネリクス内で extends を用いることで、プロパティの存在チェックをし、存在した場合はそのプロパティのvalueの型を返す条件。(だいぶややこしくなってきた。)
下記の例だと、PropertyA で T["a"]というプロパティにアクセスしているので、TestA 型ではstringが返りますが、TestB型では a というプロパティが存在しないので、定義時にエラーを返してくれるみたいです。

type PropertyA<T extends { a: unknown }> = T["a"];

interface TestA {
  a: string;
}

interface TestB {
  b: string
}

type TestAPropertyContents = PropertyA<TestA>;
// type TestAPropertyContents = string

type TestBPropertyContents = PropertyA<TestB>;
// エラー: Type 'TestB' does not satisfy the constraint '{ a: unknown; }'. Property 'a' is missing in type 'TestB' but required in type '{ a: unknown; }'

infer句

議題の中でinferを取り扱っている箇所があり、全体で話したのですが結論、よく分かりませんでした。(笑)
こちらは追い追い触れていこうと思います。
下記の記事で詳しく書かれていたのでご参考までに。
【TypeScript】 inferに詳しくなろう - Qiita 目標TypeScript のドキュメントにある上級者向けの型たち https://www.typescriptlang.org/docs/handbook/advanced-types.htmlに… Qiita

型マッピング

今回の勉強会で一番話が上がっていたのがこのマッピング。
下記は[Property in keyof Type] で オブジェクトのプロパティをmapしつつ、型をbooleanに変更した新しいオブジェクト型を生成しています。

type OnlyBooleans<Type> = {
  [Property in keyof Type]: boolean;
};

type StringsAndNumbers = {
  hoge: string
  fuga: number
}

type Booleans = OnlyBooleans<StringsAndNumbers>
// type Booleans = {
//     hoge: boolean;
//     fuga: boolean;
// }

これは実務でも結構使えそうですね。
マスター出来れば一気に表現の幅が広がると思います。

オブジェクトの余剰プロパティチェック

参加者のかっつさんが余剰プロパティチェックについて、全体に発表してくださいました。

https://twitter.com/kattsustudy?ref_src=twsrc%5Etfw


余剰プロパティチェックとはバックエンド側でよく行う処理になるのですが、かっつさんが簡単に説明してくださっていましたので引用させていただきます。

オブジェクト型に存在しないプロパティをもつオブジェクトの代入を禁止する行為のこと
https://qiita.com/ka25012/items/6cbc7b515a4f2728ee9d

こちらの内容については実際の記事を見ていただいた方が分かりやすいので、下記のリンクから是非ご覧ください。
TypeScriptの余剰プロパティチェックを過剰プロパティチェックさせる - Qiita TypeScriptを学び始めた時から疑問に思っていたことが解決できたのでそのことをまとめる。タイトルの通りTypeScriptの余剰プロパティチェックについてなのですが、口頭で説明するよりみても… Qiita
かっつさん、これで実務経験4ヶ月ってヤバすぎませんか...?

自作 Utility Types (型パズル)

今回盛り上がったのがこちらの内容。
参加者のTaigaさんがなかなかに激しめの型パズルを作成して、全体に発表してくださいました。

https://twitter.com/taiga_skg?ref_src=twsrc%5Etfw


今回の議題の「Indexed Access Types」「Conditional Types」「Mapped Types」を全て組み合わせた内容となっています。
解けた方は是非リプにてご回答を!


私自身、解説いただいてようやく理解できたのですが、これをお遊びで作ってきちゃうのがヤバいですね。(語彙力)

さいごに

今回で8回目の勉強会になりますが、だいぶレベルが上がってきましたね...
ここまで来るとジェネリクスを理解していること前提で進むので気合い入れないとキツイ...
にしても、皆さんレベルが高くて私自身、着いていくので精一杯です...(汗)
という訳で今回は「型の再利用と型パズル」会でした!
最後までご覧いただきありがとうございます!