Как вы явно устанавливаете новое свойство на `window` в TypeScript?

Я устанавливаю глобальные пространства имен для своих объектов, явно устанавливая свойство на window.

window.MyNamespace = window.MyNamespace || {};

TypeScript подчеркивает MyNamespace и жалуется, что:

Свойство 'MyNamespace' не существует при значении типа 'window' любой "

Я могу заставить код работать, объявив MyNamespace в качестве переменной окружения и отбрасывая window эксплицитно, но я не хочу этого делать.

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};

Как я могу сохранить window там и сделать TypeScript счастливым?

В качестве побочного примечания мне особенно забавно, что TypeScript жалуется, так как он говорит мне, что window имеет тип any, который определенно может содержать что угодно.

Ответ 1

Просто нашел ответ на этот вопрос в fooobar.com/questions/33645/....

declare global {
    interface Window { MyNamespace: any; }
}

window.MyNamespace = window.MyNamespace || {};

В основном вам необходимо расширить существующий интерфейс window, чтобы рассказать об этом новом свойстве.

Ответ 2

Чтобы сохранить динамику, просто используйте:

(<any>window).MyNamespace

Ответ 3

КАК ТИПИСКРИПТ ^ 3.4.3 НАСТОЯЩЕГО РЕШЕНИЯ НЕ ДЕЙСТВУЕТ

Или же...

Вы можете просто набрать:

window['MyNamespace']

и вы не получите ошибку компиляции, и она работает так же, как набрав window.MyNamespace

Ответ 4

Использование TSX? Ни один из других ответов не работал на меня.

Вот что я сделал:

(window as any).MyNamespace

Ответ 5

Принятый ответ - это то, что я использовал, но с TypeScript 0.9. * он больше не работает. Новое определение интерфейса Window похоже, полностью заменяет встроенное определение, а не увеличивает его.

Вместо этого я сделал это:

interface MyWindow extends Window {
    myFunction(): void;
}

declare var window: MyWindow;

ОБНОВЛЕНИЕ: С TypeScript 0.9.5 принятый ответ снова работает.

Ответ 6

Если вам нужно расширить объект window с помощью специального типа, который требует использования import, вы можете использовать следующий метод:

window.d.ts

import MyInterface from './MyInterface';

declare global {
    interface Window {
        propName: MyInterface
    }
}

См. "Глобальное увеличение" в разделе "Объединение декларации" Справочника: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation

Ответ 7

Глобальные являются "злом" :), я думаю, что лучший способ иметь также переносимость:

Сначала вы экспортируете интерфейс: (например:./custom.window.ts)

export interface CustomWindow extends Window {
    customAttribute: any;
}

Второй вы импортируете

import {CustomWindow} from './custom.window.ts';

Третье приведенное глобальное окно var с CustomWindow

declare let window: CustomWindow;

Таким образом, у вас также не будет красной линии в другой IDE, если вы используете существующие атрибуты объекта окна, поэтому в конце попробуйте:

window.customAttribute = 'works';
window.location.href = '/works';

Протестировано с Typescript 2.4.x и новее!

Ответ 8

Мне не нужно делать это очень часто, единственный случай, который у меня был, был при использовании Redux Devtools с промежуточным программным обеспечением.

Я просто сделал:

const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

Или вы могли бы сделать:

let myWindow = window as any;

а затем myWindow.myProp = 'my value';

Ответ 9

Для тех, кто использует Angular CLI, это довольно просто:

SRC/polyfills.ts

declare global {
  interface Window {
    myCustomFn: () => void;
  }
}

мой обычай-utils.ts

window.myCustomFn = function () {
  ...
};

Если вы используете IntelliJ, вам также необходимо изменить следующие настройки в среде IDE, прежде чем поднять новые полифиллы:

> File 
> Settings 
> Languages & Frameworks 
> TypeScript 
> check 'Use TypeScript Service'.

Ответ 10

Большинство других ответов не являются идеальными.

  • Некоторые из них просто подавляют вывод типа для магазина.
  • Некоторые другие заботятся только о глобальной переменной как о пространстве имен, но не как интерфейс/класс

Я также сталкиваюсь с подобной проблемой этим утром. Я пробовал так много "решений" на SO, но ни одно из них не выдает абсолютно никакой ошибки типа и не позволяет запускать переходы типа в IDE (webstorm или vscode).

Наконец, отсюда

https://github.com/Microsoft/TypeScript/issues/3180#issuecomment-102523512

Я нашел разумное решение, чтобы прикрепить типизации для глобальной переменной, которая действует как интерфейс/класс и пространство имен.

Пример ниже:

// typings.d.ts
declare interface Window {
    myNamespace?: MyNamespace & typeof MyNamespace
}

declare interface MyNamespace {
    somemethod?()
}

declare namespace MyNamespace {
    // ...
}

Теперь приведенный выше код объединяет типизацию пространства имен MyNamespace и интерфейса MyNamespace в глобальную переменную myNamespace (свойство window).

Ответ 11

После поиска ответов, я думаю, что эта страница может быть полезной. https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation Не уверен насчет истории слияния объявлений, но он объясняет, почему может работать следующее.

declare global {
    interface Window { MyNamespace: any; }
}

window.MyNamespace = window.MyNamespace || {};

Ответ 12

Здесь, как это сделать, если вы используете TypeScript Диспетчер определений!

npm install typings --global

Создать typings/custom/window.d.ts:

interface Window {
  MyNamespace: any;
}

declare var window: Window;

Установите свой пользовательский ввод:

typings install file:typings/custom/window.d.ts --save --global

Готово, используйте его ‌! Typescript больше не будет жаловаться:

window.MyNamespace = window.MyNamespace || {};

Ответ 13

Для справки (это правильный ответ):

Внутри файла определения .d.ts

type MyGlobalFunctionType = (name: string) => void

Если вы работаете в браузере, вы добавляете участников в контекст окна браузера, открывая интерфейс Window:

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}

Такая же идея для NodeJS:

declare module NodeJS {
  interface Global {
    myGlobalFunction: MyGlobalFunctionType
  }
}

Теперь вы объявляете корневую переменную (которая фактически будет жить в окне или глобальном)

declare const myGlobalFunction: MyGlobalFunctionType;

Затем в регулярном файле .ts, но импортированном как побочный эффект, вы фактически реализуете его:

global/* or window */.myGlobalFunction = function (name: string) {
  console.log("Hey !", name);
};

И, наконец, используйте его в другом месте в базе кода: либо

global/* or window */.myGlobalFunction("Kevin");

myGlobalFunction("Kevin");

Ответ 14

Создание настраиваемого интерфейса расширяет окно и добавляет ваше настраиваемое свойство как необязательное.

Затем позвольте customWindow, использующему пользовательский интерфейс, но оцененному с помощью исходного окна.

Он работал с [email protected]

interface ICustomWindow extends Window {
  MyNamespace?: any
}

const customWindow:ICustomWindow = window;

customWindow.MyNamespace = customWindow.MyNamespace {} 

Ответ 15

Typscript не выполняет проверку типов в свойствах строки.

window["newProperty"] = customObj;

В идеале сценарий глобальной переменной следует избегать. Я использую его иногда для отладки объекта в консоли браузера.

Ответ 16

Если вы используете Typescript 3.x, вы можете пропустить declare global часть в других ответах и вместо этого просто использовать:

interface Window {
  someValue: string
  another: boolean
}

Это работало со мной при использовании Typescript 3.3, WebPack и TSLint.

Ответ 17

Для тех, кто хочет установить вычисляемое или динамическое свойство для объекта window, вы обнаружите, что это невозможно с помощью метода declare global. Чтобы уточнить для этого варианта использования

window[DynamicObject.key] // Element implicitly has an 'any' type because type Window has no index signature

Вы можете попытаться сделать что-то вроде этого

declare global {
  interface Window {
    [DyanmicObject.key]: string; // error RIP
  }
}

Выше будет ошибка, хотя. Это связано с тем, что в Typescript интерфейсы плохо работают с вычисляемыми свойствами и выдают ошибку вроде

A computed property name in an interface must directly refer to a built-in symbol

Чтобы обойти это, вы можете перейти с предложением приведения window к <any> чтобы вы могли сделать

(window as any)[DynamicObject.key]

Ответ 18

Я хотел использовать это в библиотеке Angular (6) сегодня, и мне потребовалось некоторое время, чтобы заставить это работать как ожидалось.

Чтобы моя библиотека использовала объявления, мне пришлось использовать расширение d.ts для файла, который объявляет новые свойства глобального объекта.

Итак, в конце концов, файл закончился чем-то вроде:

/path-to-angular-workspace/angular-workspace/projects/angular-library/src/globals.d.ts

После создания не забудьте выставить его в свой public_api.ts.

Это сделало это для меня. Надеюсь это поможет.

Ответ 19

Когда я попробовал это, window набрал значение window - это означает, что есть определение, которое указывает, какие свойства и методы поддерживает window, а ваше собственное пространство имен отсутствует в этом списке.

Не можете ли вы получить нужное поведение с помощью модуля TypeScript?

module MyNamespace {
    export class Example {

    }
}

Ответ 20

Сначала вам нужно объявить объект окна в текущей области видимости.
Потому что машинопись хочет знать тип объекта.
Поскольку объект окна определен где-то еще, вы не можете переопределить его.
Но вы можете заявить об этом следующим образом:

declare var window: any;

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

Затем вы можете обратиться к своему объекту MyNamespace просто: -

window.MyNamespace

Или вы можете установить новое свойство для объекта window просто:

window.MyNamespace = MyObject

И теперь машинопись не будет жаловаться.