Как вы явно устанавливаете новое свойство для `window` в TypeScript?
Я устанавливаю глобальные пространства имен для своих объектов, явно устанавливая свойство на window
,
window.MyNamespace = window.MyNamespace || {};
TypeScript подчеркивает MyNamespace
и жалуется, что:
Свойство 'MyNamespace' не существует для значения типа 'window' any"
Я могу заставить код работать, объявив MyNamespace
в качестве переменной окружения и отбрасывая window
Ясность, но я не хочу этого делать.
declare var MyNamespace: any;
MyNamespace = MyNamespace || {};
Как я могу сохранить window
и сделать TypeScript счастливым?
В качестве примечания я нахожу особенно забавным, что TypeScript жалуется, так как он говорит мне, что window
имеет тип any
который определенно может содержать все, что угодно.
30 ответов
Только что нашел ответ на этот вопрос в ответе на другой вопрос Stackru.
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
В основном вам нужно расширить существующие window
интерфейс, чтобы рассказать о вашей новой собственности.
Чтобы сохранить динамичность, просто используйте:
(<any>window).MyNamespace
Используете TSX? Ни один из других ответов не работал для меня.
Вот что я сделал:
(window as any).MyNamespace
Или же...
Вы можете просто набрать:
window['MyNamespace']
и вы не получите ошибку компиляции, и она работает так же, как печатать window.MyNamespace
Глобальные являются "злом":), я думаю, что лучший способ иметь также переносимость:
Сначала вы экспортируете интерфейс: (например: ./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
Если вы используете Angular CLI, это действительно просто (протестировано на CLI RC.0):
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'.
Принятый ответ - то, что я использовал, но с TypeScript 0.9. * Он больше не работает. Новое определение Window
Интерфейс, кажется, полностью заменяет встроенное определение, а не расширяет его.
Я взялся за это вместо этого:
interface MyWindow extends Window {
myFunction(): void;
}
declare var window: MyWindow;
ОБНОВЛЕНИЕ: С TypeScript 0.9.5 принятый ответ снова работает.
Если вам нужно продлить 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.d.ts
например /src/@types/global.d.ts
затем определите интерфейс, например:
interface Window {
myLib: any
}
ссылка: https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-d-ts.html
Большинство других ответов не являются идеальными.
- Некоторые из них просто подавляют вывод типа для магазина.
- Некоторые другие заботятся только о глобальной переменной как о пространстве имен, но не как интерфейс / класс
Я также сталкиваюсь с подобной проблемой этим утром. Я пробовал так много "решений" на SO, но ни одно из них не выдает абсолютно никакой ошибки типа и не позволяет запускать переходы типа в IDE(webstorm или vscode).
Наконец, отсюда
Я нашел разумное решение, чтобы прикрепить типизации для глобальной переменной, которая действует как интерфейс / класс и пространство имен.
Пример ниже:
// typings.d.ts
declare interface Window {
myNamespace?: MyNamespace & typeof MyNamespace
}
declare interface MyNamespace {
somemethod?()
}
declare namespace MyNamespace {
// ...
}
Теперь код выше объединяет типизацию пространства имен MyNamespace
и интерфейс MyNamespace
в глобальную переменную myNamespace
(свойство окна).
Мне не нужно делать это очень часто, единственный случай, который у меня был, был при использовании Redux Devtools с промежуточным программным обеспечением.
Я просто сделал:
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
Или вы могли бы сделать:
let myWindow = window as any;
а потом myWindow.myProp = 'my value';
Начиная с версии 3.4 TypeScript поддерживает
globalThis
. https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#type-checking-for-globalthis
- По ссылке выше:
// in a global file:
var abc = 100;
// Refers to 'abc' from above.
globalThis.abc = 200;
«Глобальный» файл - это файл, не имеющий инструкции импорта / экспорта. Итак, декларация
var abc;
можно записать в .d.ts.
После поиска ответов, я думаю, что эта страница может быть полезной. https://www.typescriptlang.org/docs/handbook/declaration-merging.html Не уверен насчет истории слияния объявлений, но он объясняет, почему может работать следующее.
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
Используя create-react-app v3.3, я обнаружил, что самый простой способ добиться этого - расширить Window
введите автоматически сгенерированный react-app-env.d.ts
:
interface Window {
MyNamespace: any;
}
Typscript не выполняет проверку типов свойств строки.
window["newProperty"] = customObj;
В идеале следует избегать сценария с глобальной переменной. Иногда я использую его для отладки объекта в консоли браузера.
Если вы используете Typescript 3.x, вы можете опустить declare global
участвуйте в других ответах и вместо этого просто используйте:
interface Window {
someValue: string
another: boolean
}
Это работало со мной при использовании Typescript 3.3, WebPack и TSLint.
С помощью
window["MyNamespace"] = window["MyNamespace"] || {};
должно быть хорошо, как при использовании строкового свойства, но если вы действительно хотите иметь отдельное окно и упорядочить свой код, вы можете расширить объект окна:
interface MyNamespacedWindow extends Window {
MyNamespace: object;
}
declare var window: MyNamespacedWindow;
Вот как это сделать, если вы используете TypeScript Definition Manager!
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
Готово, используй это! Машинопись больше не будет жаловаться:
window.MyNamespace = window.MyNamespace || {};
Сначала вам нужно объявить объект окна в текущей области.
Потому что машинописный текст хотел бы знать тип объекта.
Поскольку объект окна определен где-то еще, вы не можете его переопределить.
Но вы можете заявить об этом так:
declare var window: any;
Это не приведет к переопределению объекта окна или не создаст другую переменную с именем window
.
Это означает, что окно определено где-то еще, и вы просто ссылаетесь на него в текущей области.
Затем вы можете ссылаться на свой объект MyNamespace просто:-
window.MyNamespace
Или вы можете установить новое свойство на window
объект просто:-
window.MyNamespace = MyObject
А теперь машинопись жаловаться не будет.
[2022]: Нам нужно расширить объект «окно» в нашем проекте React или Nextjs. Мы можем использовать следующий шаг, чтобы решить эту проблему.
Создайте папку внутри имени папки src как типы.
Создайте файл внутри имени папки типов как index.d.ts
напишите этот код в файле index.d.ts.
export {}; declare global { interface Window { NameSpace: any; } } window.NameSpace= window.NameSpace|| {};
Теперь последнее изменение.
Измените файл « tsConfig.json ». чтобы наследовать как тип модуля узла, так и наши типы.
{
"compilerOptions": {
...
"typeRoots": [
"./node_modules/@types",
"./src/types"
],
....
}
Полный и краткий ответ
1- Добавить
typeRoots
собственность на
tsconfig.json
:
{
"compilerOptions": {
...
"typeRoots": ["src/@types", "node_modules/@types"]
...
}
}
2- Продлить
Window
тип
// file: src/@types/global.d.ts
declare global {
interface Window { customProperty: <type>; }
}
Для справки (это правильный ответ):
Внутри .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");
Для тех, кто хочет установить вычисляемое или динамическое свойство на 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]
Создание настраиваемого интерфейса расширяет окно и добавляет ваше настраиваемое свойство как необязательное.
Затем позвольте customWindow, использующему пользовательский интерфейс, но оцененному с помощью исходного окна.
Это работает с typcript@3.1.3.
interface ICustomWindow extends Window {
MyNamespace?: any
}
const customWindow:ICustomWindow = window;
customWindow.MyNamespace = customWindow.MyNamespace {}
(window as { test: string } & Window & typeof globalThis).test = `Hello World`;
Я хотел использовать это в библиотеке Angular (6) сегодня, и мне потребовалось некоторое время, чтобы заставить это работать как ожидалось.
Для того, чтобы моя библиотека использовала объявления, я должен был использовать d.ts
расширение для файла, который объявляет новые свойства глобального объекта.
Итак, в конце концов, файл закончился чем-то вроде:
/path-to-angular-workspace/angular-workspace/projects/angular-library/src/globals.d.ts
После создания не забудьте выставить его в своем public_api.ts
,
Это сделало это для меня. Надеюсь это поможет.
Typescript предотвращает доступ к объекту без присвоения типа, который имеет желаемое свойство или уже назначен
any
поэтому вы можете использовать необязательную цепочку
window?.MyNamespace = 'value'
.
Я знаю, что этот вопрос может быть слишком старым для новых ответов, но недавно я сделал это с помощью метода, который здесь не упоминался -Object.defineProperty()
. Так:
Object.defineProperty(window, 'MyNamespace', {
enumerable: true,
configurable: true,
value: MyNamespace || {}
});