Programmingフルスタック開発者

TypeScriptにおけるkeyof演算子はどのように機能し、何に使用され、関数やAPIの設計にどのように影響を与えるのか?

Hintsage AIアシスタントで面接を突破

回答。

問題の背景

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

主な特徴:

  • オブジェクトの構造に依存する「キー」タイプを宣言できる。
  • プロパティのget/set関数を最大限に型安全にする — タイプミスや存在しないキーを排除。
  • TypeScript 2.7以降は、シンボルプロパティにも対応しています。

問題を含む質問。

配列の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"

型エラーとアンチパターン

  • keyofの代わりに定数文字列をキーとして使用する — 型付けが失われる。
  • unionに対するkeyofが和集合ではなく共通集合を返すと考える。
  • keyofが明示的に宣言されたキーのみを考慮し、継承されたキーを考慮しないと期待する。

実生活の例

ネガティブケース

getProperty(obj, key)という関数を文字列型のキーで作成し、存在しないキーで呼び出す — エラーは実行時にのみ発生します。

長所:

  • 汎用的なコード。

短所:

  • コンパイル時にチェックがないため、リファクタリング時にエラーが発生する可能性があり、タイプミスの脆弱性がある。

ポジティブケース

ジェネリクスを使用する: getProperty<T, K extends keyof T>()、キーの型は構造のキーに厳密に制限される。

長所:

  • 完全な型安全性で、タイプミスやキーのエラーは不可能。

短所:

  • コードは少し複雑で、ジェネリクスは初心者には理解しにくいことがある。