keyof型演算子
keyofはオブジェクト型からプロパティ名を型として返す型演算子です。たとえば、nameプロパティを持つ型に対して、keyofを使うと文字列リテラル型の"name"が得られます。
tstypePerson = {name : string;};typePersonKey = keyofPerson ;
tstypePerson = {name : string;};typePersonKey = keyofPerson ;
2つ以上のプロパティがあるオブジェクト型にkeyofを使った場合は、すべてのプロパティ名がユニオン型で返されます。
tstypeBook = {title : string;price : number;rating : number;};typeBookKey = keyofBook ;// 上は次と同じ意味になるtypeBookKey = "title" | "price" | "rating";
tstypeBook = {title : string;price : number;rating : number;};typeBookKey = keyofBook ;// 上は次と同じ意味になるtypeBookKey = "title" | "price" | "rating";
インデックス型にkeyofを用いると、インデックスキーの型が返ります。
tstypeMapLike = { [K : string]: any };typeMapKeys = keyofMapLike ;
tstypeMapLike = { [K : string]: any };typeMapKeys = keyofMapLike ;
キーがstringのインデックス型は、stringではなくstring | numberが返ります。number型のキーアクセスのobj[0]はobj["0"]と同じになるからです。
Mapped Typeskeyofを用いると、そのキーの型が返ります。
tstypeMapLike = { [K in "x" | "y" | "z"]: any };typeMapKeys = keyofMapLike ;
tstypeMapLike = { [K in "x" | "y" | "z"]: any };typeMapKeys = keyofMapLike ;
プロパティを持たないオブジェクト型にkeyofを使うとnever型が返ります。
tstypeWhat = keyof {};
tstypeWhat = keyof {};
any型にkeyofを使うとstring | number | symbol型が返ります。
tstypeAnyKeys = keyof any;
tstypeAnyKeys = keyof any;
keyofのメリット
keyofのメリットは、保守性が上がる点です。オブジェクト型とは別にプロパティ名のユニオン型を定義していると、オブジェクト型のプロパティを変更したときに、そのユニオン型のほうも修正が必要になります。keyofを使って、オブジェクト型からキーを導出するようにしておけば、変更箇所はオブジェクト型のところだけになります。
加えて、プロパティが何十個もあるようなオブジェクトを想像してみてください。そのプロパティ名のユニオン型を定義する必要が出てきたとします。その際に、プロパティ名をすべて転記するとなると、転記漏れや書き間違いもあるでしょう。そういう場合はkeyofを使うとそもそも書き写す必要がないため、便利な上に安全なコーディングができます。
keyofはMapped Typesと一緒に使われる
keyofは単体で使うことよりMapped Typesと組み合わせて使われることが多いです。