Как явно установить новое свойство для окна в TypeScript?
-
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
И теперь машинописный текст не будет жаловаться.