今回はTypeScriptがテーマです。
この記事では実例を交えて、以下について解説したいと思います。
- ジェネリクスとextends
- keyofの使い方
※TypeScriptの「ジェネリクス」自体の解説はしませんが、TS初心者向けの解説です。
前提:「オブジェクト」と「そのオブジェクトに含まれるキー」を引数に取る関数を作る
あるオブジェクトとそのキーを引数として受け取って、その値を返すだけのシンプルな関数があるとします。
function getValue(obj, key) {
return obj[key]
}
const sample = {
name: 'Taro',
age: 10
}
getValue(sample, 'name') // 'Taro'
第2引数のキー名が間違ってたりすると、この関数は正しく動きません。 (ここでは一旦、値の検証とかは置いておくとします。)
なので、第1引数に渡されたオブジェクトに含まれるキーのみを、第2引数で受け取れるようにしたいと思います。
これをTypeScriptでは、
- ジェネリクスとextends
- keyof
上記の機能を使って、わりと簡単に書くことが可能です。
ジェネリクスとkeyofを組み合わせて関数の型を書く
先ほどの関数を、TypeScriptを使って書き直したのが以下になります。
function getValue<T, U extends keyof T>(obj: T, key: U): T[U] {
return value[key];
}
const sample = {
name: 'Taro',
age: 10
}
getValue(sample, 'name') // 'Taro'
getValue(sample, 'hoge') // エラー
こうすることで、第2引数に渡される値は、第1引数に渡されたオブジェクトのキーのみとなります。
以下に、簡単にポイントを解説していきます。
extendsについて
ジェネリクス部分において、以下のように記述しています。
<T, U extends keyof T>
ジェネリクス部分でextendsを使うと、型パラメータに制約を設けることが可能となります。ここでは「型パラメータU」の型は、「keyof T」になる必要があると言っていることになります。
ちなみに「keyof T」のTは、第1引数の型パラメータTのことです。つまり、「keyof 第1引数に渡されたオブジェクト」ということですね。
では「keyof」の意味さえ分かれば、この関数の型は簡単に理解できそうです。
keyofについて
「keyof」というのはTypeScriptに用意されているキーワードで、オブジェクトの型に対して使うことが可能です。
「keyof」は、渡されたオブジェクトのキーから成るユニオン型を返します。ちょっと分かりにくいと思うので、以下のサンプルを見てみてください。
type TestType = keyof { name: string, age: number }; // TestTypeの型は 'name' | 'age' になる。
// もちろんinterfaceなどに対しても使える。
interface SampleObj {
id: string;
category: string;
}
type TestType2 = keyof SampleObj // TestType2の型は 'id' | 'category'
上記を踏まえて、以下の記述を再度見てみましょう。
function getValue<T, U extends keyof T>(obj: T, key: U): T[U] {
return value[key];
}
const sample = {
name: 'Taro',
age: 10
}
// 第1引数にオブジェクト sample を渡している。
// そのため、第2引数の型は 'name' | 'age' というユニオン型になっている。
getValue(sample, 'name') // 'Taro'
getValue(sample, 'hoge') // エラー
「keyof T」と書くことで、「第1引数として渡されたオブジェクトT」の「キー名のユニオン型」が取得できています。
そしてextendsを併用しているので、 「型パラメータU」の型は「オブジェクトTのキー名から成るユニオン型」となるわけです。
まとめ
今回は「keyof」と、「keyofとジェネリクス」を組み合わせて使う方法について解説しました。
今回はシンプルな例でしたが、TypeScriptではもっと複雑な型を表現することができます。ノウハウがたまってきたら、今後もシェアしていきたいなと考えています。