Как расширить интерфейс "Window" typescript

В моем примере я пытаюсь расширить интерфейс TS Window, чтобы включить polyfill для fetch. Почему не имеет значения. Вопрос: ", как я могу сказать TS, что window.fetch является допустимой функцией?"

Я делаю это в VS Code, v.0.3.0, который запускает TS v.1.5 (IIRC).

Объявление интерфейса внутри моего файла TS-класса, где я хочу его использовать, не работает:

///<reference path="typings/tsd.d.ts"/>

interface Window {
  fetch:(url: string, options?: {}) => Promise<any>
}
...
window.fetch('/blah').then(...); // TS objects that window doesn't have fetch

Но это нормально, если я объявляю этот же интерфейс в отдельном файле ".d.ts" и ссылаюсь на него в своем файле TS-класса.

Вот "typings/window.extend.d.ts"

///<reference path="es6-promise/es6-promise"/>
interface Window {
  fetch:(url: string, options?: {}) => Promise<any>
}

Теперь я могу использовать его в своем файле TS-класса:

///<reference path="typings/window.extend.d.ts"/>
...
window.fetch('/blah').then(...); // OK

В качестве альтернативы я могу написать расширенный интерфейс с другим именем в моем файле TS-класса, а затем использовать его в роли:

interface WindowX extends Window {
  fetch:(url: string, options?: {}) => Promise<any>
}
...
(<WindowX> window).fetch('/blah').then(...); // OK

Почему расширение интерфейса работает в "d.ts", но не на месте?

Должен ли я действительно пройти эти вращения?

Ответ 1

Если в вашем файле есть верхний уровень import или export (который должен где-то возникнуть с такой проблемой), ваш файл является внешним модулем.

Во внешнем модуле объявление интерфейса всегда создает новый тип, а не расширяет существующий глобальный интерфейс. Это имитирует общее поведение загрузчиков модулей - что вещи, объявленные в этом файле, не сливаются и не мешают вещам в глобальной области.

Причиной этого gyration является то, что в противном случае во внешнем модуле не было бы способа определить новые переменные или типы с тем же именем, что и в глобальной области.

Ответ 2

Вам понадобится declare global

declare global {
  interface Window {
    fetch:(url: string, options?: {}) => Promise<any>
  }
}

Это работает тогда:

window.fetch('/blah').then(...);