TypeScriptは、実行時(JavaScriptのように)だけでなく、コンパイル時にも式の型を推測するためのtypeof演算子をサポートしています。これにより、すでに宣言された変数、関数、またはオブジェクト構造の型を取得することができ、型付けが柔軟になり、型の重複や非同期状態のリスクを減少させることができます。
最初は、JavaScriptにおいてtypeof演算子は実行時の値の型を特定するために使用されていました。TypeScriptはこのメカニズムを拡張し、今ではコンパイル時に変数の値または関数の結果の型への参照を作成します。これは、複雑な構造、設定、モジュール間での型の再利用に非常に便利です。
手動で型を宣言する際には、構造の定義を変更してtypeやinterfaceの宣言を更新するのを忘れたり、オブジェクト間で型を間違ってコピーすることが簡単に起こります。これにより、コードの非同期状態や実行時エラーが発生する可能性があります。typeofを使用すると、型は動的に推測され、データ構造の最新の状態に常に一致します。
既存の構造や定数に対応する型を持つ変数を宣言するためにtypeof演算子を使用します:
const config = { host: "localhost", port: 8080, }; let serverCfg: typeof config; // serverCfgの型はconfigと同じ
特定の構造を返す関数の型付け:
function makeUser() { return { id: 1, name: "Alex" }; } type User = ReturnType<typeof makeUser>; // User: {id: number; name: string;}
主な特徴:
TypeScriptのtypeof演算子は実行時に実行されますか?
いいえ、型のtypeofはコンパイル時のみ機能し、実行時コードには入らず、JavaScriptのtypeof演算子は実行時に存在します。
typeofはクラスのプロパティの型を出力するために使用できますか?
はい、ただしプロパティがすでに静的に宣言されているか初期値を持っている場合のみです。private/public/protectedの場合、公開プロパティ/メソッドのみが考慮されます。
'let x: typeof y;'と'let x = y;'の間に違いはありますか?
型の観点では、両方のケースでコンパイラは自動的に型を推測します。しかし、typeofは、初期化なしで型の宣言を書くためや、ユーティリティ型とのより複雑な組み合わせを書くために使用できます。
typeofを一般的なjs型チェックtypeof x === 'string'に使用することはランタイムであり、コンパイル時の型ではありません。プロジェクトでは大きなアプリケーション設定オブジェクトが別々に型として、別々に変数として記述されています。構造が変更されると、型の更新を忘れることがあり、APIの動作エラーにつながります。
メリット: 型に対する柔軟な操作が可能で、typeまたはinterfaceを通じて型を上書きできます。
デメリット: 構造と型の非同期状態の高いリスク、保守性が悪い。
新しい変数を宣言し、APIインターフェースの型を生成する際にオブジェクト構造の最新の型を取得するためにtypeofを使用します。
メリット: 型は常に値と一致し、エラーの可能性が低く、良好なオートコンプリートがあります。
デメリット: オブジェクトが非常に複雑な場合、最終的な型は初心者には読みづらい場合があります。