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

340

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

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

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

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

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

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};

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

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

Теги:

16 ответов

337
Лучший ответ

Просто нашел ответ на этот вопрос в https://stackoverflow.com/questions/12703266/how-to-handle-warnings-for-proprietary-custom-properties-of-built-in-objects-in.

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

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

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

  • 39
    не работает с текущей версией машинописи.
  • 4
    Обратите внимание на заглавную букву W в окне. Это сбило меня с толку.
Показать ещё 10 комментариев
310

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

(<any>window).MyNamespace
  • 8
    Любые идеи, как это сделать в TSX-файл?
  • 3
    @velop stackoverflow.com/a/38964459/142098
Показать ещё 5 комментариев
161

Или...

вы можете просто ввести:

window['MyNamespace']

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

  • 12
    но вы, вероятно, получите ошибку tslint ... Если у вас есть, конечно,
  • 43
    Это полностью противоречит строгой типизации, и в этом вся идея TypeScript.
Показать ещё 7 комментариев
117

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

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

(window as any).MyNamespace
  • 2
    То же, что (<any> window).MyNamespace самом деле (<any> window).MyNamespace
  • 27
    То же самое, за исключением случаев использования TSX, потому что <any> интерпретируется как JSX, а не как приведение типа.
55

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

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

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

declare var window: MyWindow;

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

  • 2
    Это также работает с модулями, используемыми в TypeScript 2.0.8. Пример: export default class MyClass{ foo(){ ... } ... } interface MyWindow extends Window{ mc: MyClass } declare var window: MyWindow window.mc = new MyClass() Затем вы можете вызвать foo (), например, из консоль Chrome Dev Tools, например mc.foo()
  • 0
    Это очень хороший ответ, если вы не хотите объявлять что-то глобальным. С другой стороны, вам нужно вызывать declare var... в каждом файле, который вам нужен.
Показать ещё 1 комментарий
37

Если вам нужно расширить объект 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

26

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

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

export interface CustomWindow extends Window {
    customAttribute: any;
}

Во-вторых, вы импортируете

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

Третье глобальное окно var cast с CustomWindow

declare let window: CustomWindow;

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

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

Протестировано с помощью Typescript 2.4.x

  • 1
    Возможно, вы захотите рассказать, почему глобалы злые. В нашем случае мы используем нестандартизированный API для оконного объекта. На данный момент она заполнена. Это действительно зло?
  • 0
    @MathijsSegers Я не знаю, особенно ваш случай, но .. о глобальных зла это зло не только о javascript ... на каждом языке .. некоторые причины: - Вы не можете применить шаблон проектирования хорошо - Проблемы с памятью и производительностью (Вы повсюду, попробуйте прикрепить что-нибудь к объекту String и посмотрите, что произойдет, когда вы создадите новую строку) - столкновение имен, вызывающее побочный эффект для кода .. (особенно для javascript, который имеет асинхронную природу), я могу продолжить, но я думаю, что вы можете изобразить остальное...
Показать ещё 2 комментария
16

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

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

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

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

let myWindow = window as any;

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

  • 0
    В этом случае вы также можете установить пакет npm, который содержит все определения - как указано в документации.
  • 0
    Вы можете сделать это, но это не ответ на вопрос, а скорее обходной путь
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).

  • 1
    Спасибо - это единственное, что вы можете использовать в немодульном контексте.
8

Здесь, как это сделать, если вы используете 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 || {};
  • 0
    Типирование typings устарело в Typescript 2.0 (середина 2016 года) и было заархивировано владельцем.
6

Если вы используете 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'.
6

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

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

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

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

Внутри файла определения .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");
  • 0
    Спасибо, это лучший пример, который я нашел, и работает хорошо.
2

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

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

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

interface ICustomWindow extends Window {
  MyNamespace?: any
}

const customWindow:ICustomWindow = window;

customWindow.MyNamespace = customWindow.MyNamespace {} 
2

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

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

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

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

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

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

1

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

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

module MyNamespace {
    export class Example {

    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню