今更ながら頑張るTypeScript(
strict: true)をやろうという事になったのでメモ書きをつらつらと書いていきます。
今までやりたい放題anyをぶちこんでた無法地帯に秩序をもたらすべくstrictに対応させていくのはなかなか大変です。
既存のコードに型を付けていく作業中ですがなかなかサクッとやりたいことに対応するコードが出てこない+なんども同じようだけど少し違うみたいな状況で
そのたびにあれ？これってこうだっけ？と調べてということをやっている気がしてきたので最小なパターンで実装例をアウトプットしてあとで思い出しやすくします。
ということで完全にメモ書きです。
今回はConditionalTypeについて
## Conditional Type
TypeScript2.8から導入された機能
名前の通り型の定義に条件分岐を含めることができるというものです
## 特定の連想配列から特定の型の値を持つキーのリストを取得する
連想配列に対して
[]でstringの文字列を指定したときに出てくる
no index signature系の話ですね
添字に渡すキーを限定しないとエラーになるわけですが、こんなのめちゃくちゃよくやってるよ！
「連想配列に含まれるキーすべて」であれば
keyofのみで事足りるのですが
今回はその中でも特定の型の値を持つキーのみを抽出したい場合のパターンです
サンプルでコードを書いてみました。
interface Hoge { hoge1: number; hoge2: string; } interface Fuga { id: number; name: string; } interface SampleRow { a: Hoge; b: Fuga; c: string; d: boolean; e: string; } // Kは型引数Tのキー T[K] = value の値がFugaかどうかを見てマッチする場合はK. しない場合はneverのキーのUnionType type FugaPropertyNames<T> = { [K in keyof T]: T[K] extends Fuga ? K : never } [keyof T]; const row: SampleRow = { a: { hoge1: 1, hoge2: 'hoge' }, b: { id: 1, name: 'fuga' }, c: 'piyo', d: true, e: 'e' }; const field: string = 'b'; const fugaKeys: FugaPropertyNames<SampleRow>[] = ['b']; const isFugaKeys = (key: string): key is FugaPropertyNames<SampleRow> => { return fugaKeys.some(k => k === key); }; // field: string if (isFugaKeys(field)) { // field: "b" const value = row[field]; }
コメントに書いてありますが
SampleRowの中で
Fugaという型のvalueを持つキーのリストを定義させることで
タイプガードの中では
fieldの値が
"b"のみとなります
type FugaPropertyNames<T>でやりたいことはできてしまっているのですが確認の為にいくつかコードを書き換えてみます
- fugaKeysに要素を足す
- タイプガードの前で
row[field]を書く
- aの方をFugaに変更してみる -> '"a"|"b"' になる
意図通りの動作になりました
今回の場合だと
Fuga型のデータのときのみなにかやりたい場合に使えるかと思います
最初
Object.keys,
Object.valuesなどを使ってできないかも考えたのですがそれぞれループの中での型が
anyになってしまうので結局その中でタイプガードを書くことになりそうだったため別のアプローチを試みてみました。