TypeScriptにおける交差型(Intersection Types)は、元のすべての型のプロパティやメソッドを組み合わせた合成型を作成することを可能にします。これは、クラスの過剰な継承なしに柔軟で拡張可能なデータ構造を構築するための強力なツールです。この構文は、型の間に演算子 & を用いることで実現されます。
TypeScriptは最初のバージョンから、 "または" を表現するためのユニオン型(|)をサポートしていますが、時には異なる独立したインターフェースや型からの多数のプロパティを持つオブジェクトを記述する必要が生じます。このようなとき、交差型(&)が利用されます — オブジェクトはすべてのインターフェースのすべてのプロパティを満たさなくてはなりません。
主な課題の一つは、交差型のプロパティ名が同じであることによる衝突や、型の不一致、さらにプライベートまたはプロテクトされたフィールドを持つクラスを結合した場合の最終的な複合型の整合性です。また、しばしば交差型とユニオン型が混同され、予期しないコンパイルエラーやオブジェクトの操作に問題が生じます。
交差型は結合される型からすべてのプロパティを集約し、各プロパティについて両方の型に一致させる必要があります(名前が一致する場合)。これは、インターフェースやtypeエイリアスの両方に使用されます。
interface A { foo: string; } interface B { bar: number; } type AB = A & B; const item: AB = { foo: "hello", bar: 123 }; // 正常
同じ名前のプロパティが交差する場合、型が一致する必要があります。そうでなければエラーが発生します:
interface X { val: string; } interface Y { val: number; } // type Z = X & Y; // エラー:valの不一致
主な特徴:
& は両方の型のすべてのプロパティを組み合わせます(インターフェースとtypeエイリアス)。型が交差し、一部のプロパティが互換性のない型の場合、何が起きますか?(例えば、1つのプロパティがstring、もう1つがnumber)
コンパイルエラーになります。なぜなら、プロパティは同時にstringとnumberになることはできないからです。
プライベートまたはプロテクトされたプロパティを持つクラスを交差させることはできますか?
できますが、そのようなフィールドが異なるアクセス型で同じ名前を持つ場合、結果は無効になり、TypeScriptはエラーを出力します。
交差型はユニオン型(|)とどのように異なりますか?
交差型(A & B)は、オブジェクトが両方の型であることを要求しますが、ユニオン型(A | B)は、いずれか1つの型であればよいです。例えば:
type U = A | B; // fooかbarのいずれか、または両方 タイプ I = A & B; // 両方のプロパティが必要
開発者がいくつかの不一致なインターフェースを交差させて型を作成し、プロパティ間で衝突が生じ、デバッグが困難な型エラーが発生します。
長所: 複数の型の機能を迅速に統合できる。
短所: コードがコンパイルされないか、暗黙のバグを含む可能性があり、デバッグが困難である。
関数を独立したインターフェースに分け、それを交差型で注意深く統合して最終的な合成オブジェクトを形成します。
長所: スケーラビリティ、テストや拡張の簡易性、厳密な契約。
短所: インターフェースの設計と調整に追加の労力が必要。