Declaration Merging(宣言のマージ)とは、同じ名前の宣言を一つの型/エンティティに結合する、TypeScript特有のメカニズムです。これはインターフェース、名前空間、関数に対して機能します。
interface User { name: string; } interface User { age: number; } const u: User = { name: 'Vasya', age: 42 }; // OK
function helper() {} namespace helper { export function extra() {} } helper.extra(); // OK
異なるインターフェースの空間で同じ名前のメソッドがマージされる場合、もしそのシグネチャが異なったらどうなりますか?
回答:
異なるマージインターフェースで同じ名前のメソッドを宣言すると、TypeScriptは最終的なインターフェースでこれらのメソッドを「オーバーロード」しようとします。しかし、もしシグネチャが互換性がない場合(オーバーロードできない場合)、コンパイルエラーが発生します。
例:
interface Foo { bar(a: number): void } interface Foo { bar(a: string): void } // OK: オーバーロード interface Foo { bar(a: number[]): void } // エラー: 互換性のないシグネチャ
物語
あるプロジェクトで、異なる機能のためにdeclaration mergingを通じて外部インターフェースWindowを拡張していました: あるチームはwindow.myFeature: booleanを追加し、別のチームはwindow.myFeature: numberを追加しました。マージは型のエラーを引き起こし、コンパイラは一般的なビルド時にのみ衝突をキャッチしました — 誰かが急いでリネームする必要がありました。
物語
誤って異なるメソッドシグネチャを持つ二つのArrayHelperインターフェースを宣言し、「両方のバリエーションが利用可能」になることを期待していました。実際には、最初のシグネチャが二つ目を覆い、IDEのオートコンプリートに不具合を引き起こし、新しいモジュールとの統合中にバグが発生しました。
物語
declaration mergingを通じて関数を「拡張」するために名前空間を使用していた開発者は、名前空間内でexportを誤って宣言し、関数が利用できなくなりました。レビューの後、正しいexportがなければマージが機能せず、プロパティが関数に出現しなかったことが明らかになりました。