問題の背景
TypeScriptは最初からオブジェクトの厳密な型付けと、JavaScriptでより予測可能なコードを書くために設計されていました。オブジェクトのプロパティへのアクセスの安全性を確保するためのツールの一つがkeyof演算子であり、これはTypeScript 2.1で登場しました。これにより、宣言されたオブジェクト型に存在する文字列(およびシンボル)のキーのセットを表す型を作成することができます。
問題
純粋なJavaScriptでは、オブジェクトのプロパティは任意の文字列で要求でき、もし誤るとundefinedや実行時にのみ発見されるエラーになります。厳密な型付けがないと、タイプミスをしたり、リファクタリング中にキーの文字列の更新を忘れたりすることが簡単です。また、特定のオブジェクトまたは型の正しいキーのみを受け取る関数を作成する必要があることがよくあります。
解決策
keyof演算子は、型のすべてのキーからユニオン型を生成します。これによって許可されるキーを制限し、APIの安全性を向上させ(例えばgetter/setter関数用に)、ジェネリックユーティリティ型を作成することができます。
コード例:
type User = { name: string; age: number; active: boolean }; type UserKey = keyof User; // "name" | "age" | "active" function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const user: User = { name: 'Tom', age: 33, active: true }; const age = getProp(user, 'age'); // 年齢の型はnumber
主な特徴:
配列のkeyofは何を返し、インデックスを取得できるか?
配列に対するkeyofは、実際に配列がJavaScriptで持っているオブジェクトのキーの型を返します。通常はインデックスの文字列と、配列の特別なプロパティです。
コード例:
type A = keyof number[]; // "length" | "toString" | "pop" | ... | number
keyofはunion-typesのキーを返すことができるか?
はい、keyofはunion型から両方のオブジェクトのキーの共通部分を返します。
コード例:
type A = {a: string, b: number } type B = {b: number, c: boolean } type C = keyof (A | B); // "b"
オブジェクトのプロパティがオプショナルな場合はどうなるか?keyofは「?」をサポートしているか?
はい、オプショナルなプロパティも結果の型のキーに含まれますが、それがランタイムでオブジェクトに必ず存在することを意味するわけではありません。
コード例:
type D = { a: string; b?: number }; type DK = keyof D; // "a" | "b"
getProperty(obj, key)という関数を文字列型のキーで作成し、存在しないキーで呼び出す — エラーは実行時にのみ発生します。
長所:
短所:
ジェネリクスを使用する: getProperty<T, K extends keyof T>()、キーの型は構造のキーに厳密に制限される。
長所:
短所: