質問の背景
デフォルトでは、TypeScriptは関数の型シグネチャを照合する際に一定の「ゆるさ」を許容しており、逆変換関数と非逆変換関数が互換性があると見なされています。TypeScript 2.6から導入されたstrictFunctionTypesオプションは、関数の型の厳密な検査を保証し、特に大規模なコードベースでは多くのエラークラスを防止します。
問題点
厳密な検査がない場合、ハンドラー関数やコールバックが、より多くまたはより特定的なタイプのパラメータを受け取るという状況が発生し、これが開発者にとって見えないことがあります。これは、返される型の共変性や引数の反変性に関連するランタイムエラーを引き起こします。
解決策
strictFunctionTypesオプションは、関数のパラメータ型に対して厳密な反変性を導入します。これにより、関数は、元の型のパラメータが宛先のパラメータのスーパタイプである場合にのみ互換性があります。
コードの例:
type Animal = { name: string }; type Cat = { name: string; meow: () => void }; let animalHandler: (a: Animal) => void; let catHandler: (c: Cat) => void; animalHandler = catHandler; // strictFunctionTypesエラー: 引数が特定的すぎる catHandler = animalHandler; // 許可される、CatはAnimalのサブタイプ
主な特徴:
厳密なチェックが導入される前に、より特定的なパラメータタイプのハンドラーを割り当てることはできたか?
はい、strictFunctionTypesが有効になる前は、TypeScriptは、より特定的な関数を一般的な関数に割り当てることを許可していました。これは、ランタイムエラーにつながることがありました。
enum E { A, B } const f: (e: E) => void = (e: E.A) => {} // strictFunctionTypesなし: 許可される
strictFunctionTypesはオプションパラメータのコールバックにどのように影響するか?
関数のコールバックのパラメータがオプションパラメータになる場合、厳格なチェックは、必須パラメータの数が多い関数の位置に、必須パラメータが少ない関数を使用することを許可しません。これは、コールバックが必要なデータを受け取れない状況を防ぎます。
古いプロジェクトでstrictFunctionTypesを有効にすると互換性の問題が発生するか?
はい、コンパイルエラーが新たに発生するリスクがあるため、多くの関数やハンドラーが反変性の違反を伴ってお互いに割り当てられている可能性があります。これは、コールバックや、厳密な型指定なしでのサードパーティライブラリのAPIの使用時に最も一般的に見られます。
大規模なプロジェクトで、イベントハンドラーがより特定的な型(一般的なEventの代わりにMouseEvent)を受け取ります。これは厳密なオプションが有効にされるまで検出されず、異なるイベント源で実行時エラーを引き起こします。
利点:
欠点:
プロジェクトは最初からstrictFunctionTypesを使用しています。新しいハンドラーを追加すると、型間のすべての不一致がコンパイラによって自動的に検出されます。コードはタイポに対してより耐性があり、メンテナンスが容易になります。
利点:
欠点: