Declaration MergingはTypeScriptのユニークな特徴であり、同じ名前の複数の宣言を1つのエンティティに統合することを可能にします。これはTypeScriptがJavaScriptの上に型付けを行う歴史と関連しています:多くのサードパーティライブラリがインターフェース、関数、名前空間を宣言し、TypeScriptはライブラリの元のコードを変更することなくそれらを拡張できる必要がありました。
複雑なAPIやサードパーティのJSライブラリの型付けでは、責任を分割する必要がある場合があります。たとえば、モジュールの型を拡張したり、インターフェースにフィールドを追加したり、名前を統合したりすることです。しかし、ほとんどの言語はそのような宣言の統合をサポートしていません。
TypeScriptは同じ名前のインターフェース、名前空間、関数、クラスの宣言をマージ(merge)することを可能にし、APIを拡張するための柔軟性を提供します。これは、サードパーティの型を拡張したり、ライブラリにカスタムメソッドを追加したり、モジュラーコードを整理するために使用されます。
コード例:
// インターフェースのマージ interface User { id: number; } interface User { name: string; } const u: User = { id: 1, name: "Jack" }; // 名前空間 + 関数のマージ function greet() { return "Hi!"; } namespace greet { export function loud() { return "HI!"; } } greet(); // "Hi!" greet.loud(); // "HI!"
主な特徴:
インターフェースのようにtype aliasを統合することはできますか?
いいえ、type aliasは統合できません。同じ名前の複数のtypeを宣言しようとするとコンパイルエラーが発生します。
type T = { a: string }; type T = { b: number }; // エラー
TypeScriptはインターフェースや名前空間のフィールドをランダムな順序で挿入しますか?
マージされた構造は常に宣言の順序で構築されます — 同じプロパティ名がある場合、最後の宣言が「勝ちます」。
インターフェースのメソッドは1つの関数に統合されますか?
いいえ、異なるインターフェースに同じ名前のメソッドがあっても1つの関数に統合されることはありません — シグネチャが一致していても、TypeScriptは「両方」のバージョンを実装することを許可しません。
企業が異なるフィールドと異なる型を持つグローバルインターフェースWindowを2回定義している。ビルド中に問題が見えず、実行時に予期しない型の競合が発生します。
利点:
欠点:
サードパーティライブラリに対してd.tsファイルが記述され、APIインターフェースがライブラリ自体を変更することなく個別のモジュールで拡張され、すべての拡張が文書化され、命名ポリシーがWikiに記載されている。
利点:
欠点: