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

StackOverflow https://stackoverflow.com//questions/12709074

  •  13-12-2019
  •  | 
  •  

Вопрос

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

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

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

Свойство «mynamespace» не существует в значении окна типа «любое» любое »

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

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};

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

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

Это было полезно?

Решение

Только что нашел ответ на этот вопрос в ответ на другой вопрос StackOverflow.

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

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

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

Другие советы

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

(<any>window).MyNamespace

С ТИПОПИСАНИЯ ^ 3.4.3 ЭТО РЕШЕНИЕ БОЛЬШЕ НЕ РАБОТАЕТ

Или...

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

window['MyNamespace']

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

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

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

(window as any).MyNamespace

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

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

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

declare var window: MyWindow;

ОБНОВЛЯТЬ: В TypeScript 0.9.5 принятый ответ снова работает.

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

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

export interface CustomWindow extends Window {
    customAttribute: any;
}

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

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

Третье окно глобальной переменной с CustomWindow

declare let window: CustomWindow;

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

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

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

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

окно.д.ц

import MyInterface from './MyInterface';

declare global {
    interface Window {
        propName: MyInterface
    }
}

См. «Глобальное расширение» в разделе «Слияние объявлений» Руководства: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation

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

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

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

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

let myWindow = window as any;

а потом myWindow.myProp = 'my value';

Для тех, кто использует Угловой интерфейс командной строки это просто:

src/polyfills.ts

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

мой-custom-utils.ts

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

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

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

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

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

Сегодня утром я тоже столкнулся с подобной проблемой.Я пробовал так много «решений» для 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(свойство окна).

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

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

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

Вот как это сделать, если вы используете Менеджер определений 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 || {};

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

interface Window {
  someValue: string
  another: boolean
}

У меня это сработало при использовании Typescript 3.3, WebPack и TSLint.

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

window["newProperty"] = customObj;

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

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

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

type MyGlobalFunctionType = (name: string) => void

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

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");

Создайте собственный интерфейс, расширяющий окно, и добавьте свое пользовательское свойство как необязательное.

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

Это работало с typescript@3.1.3.

interface ICustomWindow extends Window {
  MyNamespace?: any
}

const customWindow:ICustomWindow = window;

customWindow.MyNamespace = customWindow.MyNamespace {} 

Для тех, кто хочет установить вычисляемое или динамическое свойство в 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]

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

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

В итоге файл получился примерно таким:

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

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

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

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

declare var window: any;

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

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

window.MyNamespace

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

window.MyNamespace = MyObject

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top