※ こちらはミツモアAdvent Calendar 2021の13日目の記事です。
ミツモアは「リモートワークが増えてエアコンを綺麗にしたい」「引っ越しで出た不用品を回収してもらいたい」といった生活のあらゆるシーンであなたにぴったりの専門家を無料で探せるサービスですので、ぜひ気軽に使ってみてください!
今回はType Guardを使った型定義について話そうと思います。
ミツモアは元々JavaScriptで書かれていましたが、TypeScriptに移行しました。
移行するにあたり各所に型を書いていっていますが、型定義が緩い箇所が存在していてそれを定義し直したりしています。
今回はその一例を紹介しようと思います
Type Guardとは
Type Guard とは、特定の型かどうかをbooleanで返す関数の事です。
TypeScript: Documentation - Advanced Types
interface XXX { type: 'xxx' } const isXXType = (item: any): item is XXX => { return item.type === 'xxx' } if (isXXXType(item)) { /** XXX typeの時の処理 **/ /** ここではitemの型はXXXとして推論される **/ }
isXXXType()
で判定されたifの中ではitemはXXX
として型補完がされます。
実行時に動くコードになり実装の記述としても処理がわかりやすくなります。
注意点としてはType Guardの記述をミスると間違ったまま動くという点があります。
ミツモアのチャット
ミツモアでは依頼者と事業者の間でチャットができるのですが、チャットには色々なタイプがあります。
- テキスト
- 画像
- ファイル
- etc...
このタイプの情報をtype
フィールドに持っています。
それぞれのタイプに必要なデータを保持するフィールドがチャットのDBには存在しますが、あるtypeで利用されるフィールドは他のタイプのチャットからすると不要なフィールドです。
また、タイプを跨いで共有されているフィールドもあります。
ここでは仮にtypeがtext
の時にはtext
フィールドが、image
の時にはimageKey
があるとします
ミツモアでは以下のように定義していました
interface Chat { _id: string type: 'text' | 'image' | 'file' | ... text?: string imageKey?: string }
他のタイプでは存在しないフィールドであるが故に基本的にフィールドをoptionalで定義することになってしまっています。
また、知識として画像チャットの時にはimageKey
だけが存在することを実装者は知っていますが、型の情報からはこの知識が得られません。
そこでType Guardを使って安全に型を書くことにしました
interface TextChat { type: 'text' text: string } interface ImageChat { type: 'image' text: string imageKey: string } type Chat = TextChat | ImageChat const isTextChat = (chat: any): chat is TextChat => chat.type === 'text' const isImageChat = (chat: any): chat is ImageChat => chat.type === 'image' const doSomething = (chat: Chat) => { chat.imageKey // 常にChat型に存在するわけではないのでtypeエラー if (isTextChat(chat)) { return chat.imageKey // TextChat型には存在しないのでtypeエラー } if (isImageChat(chat)) { return chat.imageKey } }
型とTypeGuardをこのように定義することで、typeがtextなのにimageKeyにアクセスしようとすると型エラーにすることができます。
また、TypeGuardを使わないでアクセスしようとする時は当てはまりうる全ての型(ImageChat
とTextChat
)に存在しない場合はエラーとなります。
そのため強制的にTypeGuardを使うことになり、型の安全性が自動的に高まります。
まとめ
optionalを使って緩く書かれてしまっている型を安全にわかりやすく定義できるTypeGuardについて説明しました。
何でもかんでもTypeGuardを使わないとダメなように書いてしまうと実装コストが上がってしまったり、JavaScript的には不要なコードを書かなければいけなかったりするのでうまく付き合っていくことが大事かなと思います。
現在、事業拡大を進めておりエンジニア・デザイナー・PdMを積極採用中です! ぜひWantedlyのリンクからカジュアル面談をしましょう。TwitterのDMでもお待ちしております。