How do you explicitly set a new property on `window` in TypeScript?
。
up vote279down votefavorite
60
I setup global namespaces for my objects by explicitly setting a property on window
.
window.MyNamespace = window.MyNamespace || {};
TypeScript underlines MyNamespace
and complains that:
The property 'MyNamespace' does not exist on value of type 'window' any"
I can make the code work by declaring MyNamespace
as an ambient variable and dropping the window
explicitness but I don't want to do that.
declare var MyNamespace: any;
MyNamespace = MyNamespace || {};
How can I keep window
in there and make TypeScript happy?
As a side note I find it especially funny that TypeScript complains since it tells me that window
is of type any
which by definitely can contain anything.
asked Oct 3 '12 at 13:01
7,90993956
add a comment
14 Answers
up vote282down vote
To keep it dynamic, just use:
(<any>window).MyNamespace
answered Jun 9 '15 at 19:18
3,0141107
-
6
Any ideas how to do this in a tsx file? – velop Mar 16 '17 at 7:06
-
3
@velop stackoverflow.com/a/38964459/142098 – Doug Apr 7 '17 at 18:29
-
1
I guess this only works without
-noImplicitAny
... – martin Apr 18 '17 at 19:16 -
1
@martin: The <any> makes it explicit, so it works just fine, I believe. Others: If you are using Typescript with React or other JSX environment (resulting in TSX syntax) you'll have to use
as
instead of<>
. See @david-boyd's answer below. – Don Aug 22 '17 at 15:59 -
6
I had to use (window as any).MyNamespace – ArsalanDotMe Sep 19 '17 at 9:37
up vote277down voteaccepted
Just found the answer to this in another StackOverflow question's answer.
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
Basically you need to extend the existing window
interface to tell it about your new property.
8,04923374
answered Oct 3 '12 at 13:46
7,90993956
-
32
does not work with the current version of typescript. – citykid Apr 1 '13 at 17:24
-
4
Note the capital W in Window. That tripped me up. – ajm Oct 9 '13 at 20:55
-
2
I couldn't get this to compile with tsc 1.0.1.0. Blake Mitchell's answer did work for me, though. – Pat Oct 13 '14 at 17:51
-
33
Be aware that this only works when declared in a separate
.d.ts
file. It does not work when used in a.ts
file that uses imports and exports itself. See this answer. – cdauth Mar 9 '16 at 14:21 -
10
The
declare global { interface Window { ... } }
works with TypeScript 2.5.2, no need for.d.ts
file as mentioned above – tanguy_k Sep 3 '17 at 20:29
up vote139down vote
Or...
you can just type:
window['MyNamespace']
and you wont get a compile error and it works the same as typing window.MyNamespace
answered Nov 20 '12 at 19:36
8,02543557
-
11
but you will probably get a tslint error... If you have one of course – smnbbrv Jan 7 '16 at 12:34
-
34
This completely flies in the face of strong typing, the whole idea behind TypeScript. – d512 Jan 28 '16 at 23:55
-
5
@user1334007 using globals does as well. However, some legacy code requires it. – nathancahill Mar 1 '16 at 17:03
-
@user1334007 this is the example when you need this stuff: andrewhfarmer.com/aws-sdk-with-webpack– SMSk Dec 5 '16 at 15:18
-
2
@Ramesh
window['MyNamespace']()
(just add brackets) – iBaff Dec 21 '17 at 18:14
up vote105down vote
Using TSX? None of the other answers were working for me.
Here's what I did:
(window as any).MyNamespace
answered Aug 15 '16 at 23:25
3,94531513
-
1
Same as
(<any> window).MyNamespace
actually – Dmitry Parzhitsky May 15 '17 at 12:17 -
20
It is the same except when using TSX, because the
<any>
gets interpreted as JSX, not a type cast. – Jake Boone May 15 '17 at 20:40
add a comment
up vote49down vote
The accepted answer is what I used to use, but with TypeScript 0.9.* it no longer works. The new definition of the Window
interface seems to completely replace the built-in definition, instead of augmenting it.
I have taken to doing this instead:
interface MyWindow extends Window {
myFunction(): void;
}
declare var window: MyWindow;
UPDATE: With TypeScript 0.9.5 the accepted answer is working again.
answered Aug 27 '13 at 21:22
1,76211619
-
2
This works also with modules as used by TypeScript 2.0.8. Example:
export default class MyClass{ foo(){ ... } ... }
interface MyWindow extends Window{ mc: MyClass }
declare var window: MyWindow
window.mc = new MyClass()
Then you can call foo() e.g. from the Chrome Dev Tools console likemc.foo()
– Martin Majewski Dec 5 '16 at 16:43 -
This is a very nice answer if you don't want to declare something as global. On the other side, you need to call
declare var...
in every file you need. – Puce May 25 at 12:23
add a comment
up vote30down vote
If you need to extend the window
object with a custom type that requires the use of import
you can use the following method:
window.d.ts
import MyInterface from './MyInterface';
declare global {
interface Window {
propName: MyInterface
}
}
See 'Global Augmentation' in the 'Declaration Merging' section of the Handbook: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation
answered Oct 23 '16 at 15:24
3,31133257
add a comment
up vote22down vote
Global are "evil" :), i think the best way to have also the portability is:
First you export the interface: (eg: ./custom.window.ts)
export interface CustomWindow extends Window {
customAttribute: any;
}
Second you import
import {CustomWindow} from './custom.window.ts';
Third cast global var window with CustomWindow
declare let window: CustomWindow;
In this way you don't have also red line in different IDE if you use with existent attributes of window object, so at the end try:
window.customAttribute = 'works';
window.location.href = '/works';
Tested with Typescript 2.4.x
5,06423656
answered Jul 27 '17 at 13:28
1,0201329
add a comment
up vote8down vote
Here's how to do it, if you're using TypeScript Definition Manager!
npm install typings --global
Create typings/custom/window.d.ts
:
interface Window {
MyNamespace: any;
}
declare var window: Window;
Install your custom typing:
typings install file:typings/custom/window.d.ts --save --global
Done, use it! Typescript won't complain anymore:
window.MyNamespace = window.MyNamespace || {};
answered Nov 19 '16 at 21:31
2,73862944
add a comment
up vote7down vote
Most of the other answers are not perfect.
- Some of them just suppress the type inference for shop.
- Some of the others only cares about global variable as namespace, but not as interface/class
I also encounter the similar problem this morning. I tried so many "solutions" on SO, but none of them produce no type error absolutely and enable triggering type jumping in IDE(webstorm or vscode).
Finally, from here
https://github.com/Microsoft/TypeScript/issues/3180#issuecomment-102523512
, I find a reasonable solution to attach typings for global variable which acts as interface/class and namespace both.
Example is below:
// typings.d.ts
declare interface Window {
myNamespace?: MyNamespace & typeof MyNamespace
}
declare interface MyNamespace {
somemethod?()
}
declare namespace MyNamespace {
// ...
}
Now, the code above merges the typings of namespace MyNamespace
and interface MyNamespace
into the global variable myNamespace
(the property of window).
answered May 19 '17 at 3:26
2,6111231
-
1
Thanks - this is the only one you can seemingly use in an ambient non-module context. – Tyler Sebastian Jul 26 '17 at 23:31
add a comment
up vote7down vote
I don't need to do this very often, the only case I have had was when using Redux Devtools with middleware.
I simply did:
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
Or you could do:
let myWindow = window as any;
and then myWindow.myProp = 'my value';
answered Jun 6 at 13:13
31338
add a comment
up vote5down vote
If you're using the Angular CLI it's really straightforward (tested on CLI RC.0):
src/polyfills.ts
declare global {
interface Window {
myCustomFn: () => void;
}
}
my-custom-utils.ts
window.myCustomFn = function () {
...
};
I'm using IntelliJ, so I also needed to change the following setting in the IDE before my new polyfills picked up:
> File
> Settings
> Languages & Frameworks
> TypeScript
> check 'Use TypeScript Service'.
answered Mar 21 '17 at 13:38
13.2k84342
add a comment
up vote3down vote
For reference (this is the correct answer):
Inside a .d.ts
definition file
type MyGlobalFunctionType = (name: string) => void
If you work in the browser, you add members to the browser's window context by reopening Window's interface:
interface Window {
myGlobalFunction: MyGlobalFunctionType
}
Same idea for NodeJS:
declare module NodeJS {
interface Global {
myGlobalFunction: MyGlobalFunctionType
}
}
Now you declare the root variable (that will actually live on window or global)
declare const myGlobalFunction: MyGlobalFunctionType;
Then in a regular .ts
file, but imported as side-effect, you actually implement it:
global/* or window */.myGlobalFunction = function (name: string) {
console.log("Hey !", name);
};
And finally use it elsewhere in the codebase, with either:
global/* or window */.myGlobalFunction("Kevin");
myGlobalFunction("Kevin");
answered Apr 20 '17 at 15:50
2,0251314
add a comment
up vote3down vote
After finding answers around, I think this page might be helpful.https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation Not sure about the history of declaration merging, but it explains why the following could work.
declare global {
interface Window { MyNamespace: any; }
}
window.MyNamespace = window.MyNamespace || {};
448417
answered Mar 16 '17 at 17:38
12417
add a comment
up vote2down vote
I wanted to use this in an Angular (6) library today and it took me a while to get this to work as expected.
In order for my library to use declarations I had to use the d.ts
extention for the file that declares the new properties of the global object.
So in the end, the file ended up with something like:
/path-to-angular-workspace/angular-workspace/projects/angular-library/src/globals.d.ts
Once created, don't forget to expose it in your public_api.ts
.
That did it for me. Hope this helps.