ПрограммированиеTypescript разработчик

Расскажите про механизм Declaration Merging в TypeScript. Как он работает для интерфейсов, функций и пространств имён (namespace), и какие здесь есть ловушки?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Declaration Merging (слияние деклараций) — уникальный механизм TypeScript, позволяющий объединять объявления с одинаковым именем в единый тип/сущность. Это работает для интерфейсов, пространств имён и функций.

  1. Интерфейсы: объявления интерфейса с одним именем сливаются в один большой интерфейс:
interface User { name: string; } interface User { age: number; } const u: User = { name: 'Vasya', age: 42 }; // OK
  1. Функции + namespace: функция и пространство имён с одинаковым именем сливаются — статические методы агрегируются:
function helper() {} namespace helper { export function extra() {} } helper.extra(); // OK
  1. Namespace + enum и namespace + class: также возможно слияние для расширения классов и enum'ов статическими свойствами.

Вопрос с подвохом.

Как происходит слияние методов с одинаковыми именами в разных пробелах интерфейса, и что будет, если их сигнатуры различаются?

Ответ:

Если вы объявите в разных 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 не работает и свойства не появляются на функции.