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
Как происходит слияние методов с одинаковыми именами в разных пробелах интерфейса, и что будет, если их сигнатуры различаются?
Ответ:
Если вы объявите в разных merge-интерфейсах методы с одинаковым именем, TypeScript попытается "перегрузить" эти методы в итоговом интерфейсе. Однако, если сигнатуры несовместимы (не могут быть перегружены), это приведёт к ошибке компиляции.
Пример:
interface Foo { bar(a: number): void } interface Foo { bar(a: string): void } // OK: перегрузки interface Foo { bar(a: number[]): void } // Ошибка: несовместимые сигнатуры
История
В одном проекте расширяли сторонний интерфейс Window через declaration merging для разных фичей: одна команда добавила window.myFeature: boolean, другая window.myFeature: number. Merge вызвал ошибку типов, и компилятор поймал конфликт только при общем сборе — кому-то пришлось быстро делать rename.
История
По ошибке объявили два интерфейса ArrayHelper с разными сигнатурами методов, ожидая, что они сложатся в "оба варианта доступны". В реальности первая сигнатура перекрыла вторую, что привело к неправильному автодополнению в IDE и багу во время интеграции с новым модулем.
История
Используя пространство имён для "расширения" функции через declaration merging, разработчик неправильно объявил export внутри namespace, и функция оказалась недоступной. Только после review выяснили, что без правильного export merge не работает и свойства не появляются на функции.