ProgrammingTypeScript開発者

TypeScriptにおけるDeclaration Mergingメカニズムについて教えてください。インターフェース、関数、名前空間(namespace)に対してどのように機能し、どのような落とし穴がありますか?

Hintsage AIアシスタントで面接を突破

回答。

Declaration Merging(宣言のマージ)とは、同じ名前の宣言を一つの型/エンティティに結合する、TypeScript特有のメカニズムです。これはインターフェース、名前空間、関数に対して機能します。

  1. インターフェース: 同じ名前のインターフェースの宣言は一つの大きなインターフェースに統合されます:
interface User { name: string; } interface User { age: number; } const u: User = { name: 'Vasya', age: 42 }; // OK
  1. 関数 + 名前空間: 同じ名前の関数と名前空間は統合され、静的メソッドが集約されます:
function helper() {} namespace helper { export function extra() {} } helper.extra(); // OK
  1. 名前空間 + enum および 名前空間 + class: クラスやenumの静的プロパティの拡張に対しても統合が可能です。

フックのある質問。

異なるインターフェースの空間で同じ名前のメソッドがマージされる場合、もしそのシグネチャが異なったらどうなりますか?

回答:

異なるマージインターフェースで同じ名前のメソッドを宣言すると、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がなければマージが機能せず、プロパティが関数に出現しなかったことが明らかになりました。