Reputation: 35267
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.
Upvotes: 1303
Views: 869861
Reputation: 57
One liner with simple Typescript:
(window as typeof window & { myProperty: any }).myProperty
Upvotes: -1
Reputation: 21
// Typescript 5.2.2
// You just code it in xxx.d.ts for extend window:
declare interface Window {
foo: string;
}
Upvotes: 1
Reputation: 497
Two method:
#1: create a global.d.ts
file, this file name can be random but it needs to be included in TypeScript checked directory, then you can use declare global
namespace to define new properties on Window
:
declare global {
interface Window {
myCustomFn: () => void;
}
}
// At least one export statement
export {};
#2: create a global.d.ts
file, this file name can be random but it needs to be included in TypeScript checked directory, and you can't use any import
or export
statement in this file. then you can just use interface
to define new properties on Window
:
//~ just need this
interface Window {
myProperty: string;
}
Upvotes: 11
Reputation: 39035
It's straightforward:
File src/polyfills.ts
declare global {
interface Window {
myCustomFn: () => void;
}
}
File my-custom-utils.ts
window.myCustomFn = function () {
...
};
If you're using IntelliJ IDEA, you also needed to change the following setting in the IDE before your new polyfills pick up:
> File
> Settings
> Languages & Frameworks
> TypeScript
> check 'Use TypeScript Service'.
Upvotes: 111
Reputation: 457
[2022]:We have to extend the "window" object in our React or Nextjs project . We can use the following step to solve this issue.
Make a folder inside src folder name as types.
Make a file inside types folder name as index.d.ts
write this code inside index.d.ts file.
export {};
declare global {
interface Window {
NameSpace: any;
}
}
window.NameSpace= window.NameSpace|| {};
Now one last change .
Change the "tsConfig.json" file. to inherit both the node module type and our types.
{
"compilerOptions": {
...
"typeRoots": [
"./node_modules/@types",
"./src/types"
],
....
}
Upvotes: 13
Reputation: 416
// In typings.d.ts(is Global)
export declare global {
interface Window {
__PUBLIC__: string;
}
}
Upvotes: 17
Reputation: 4782
(window as { test: string } & Window & typeof globalThis).test = `Hello World`;
Upvotes: 5
Reputation: 10957
typeRoots
property to tsconfig.json
:{
"compilerOptions": {
...
"typeRoots": ["src/@types", "node_modules/@types"]
...
}
}
Window
type// file: src/@types/global.d.ts
declare global {
interface Window { customProperty: <type>; }
}
Upvotes: 12
Reputation: 507
From the version 3.4, TypeScript has supported globalThis
. See Type-checking for globalThis.
From the above link:
// in a global file:
var abc = 100;
// Refers to 'abc' from above.
globalThis.abc = 200;
window.abc = 300; // window object can also be used.
A "global" file is a file which does not have any import/export statements. So the declaration var abc;
can be written in .d.ts.
Upvotes: 22
Reputation: 104870
Using
window["MyNamespace"] = window["MyNamespace"] || {};
should be all right as it is using a string property, but if you really want to have a separated window and organised your code, you can extend the window object:
interface MyNamespacedWindow extends Window {
MyNamespace: object;
}
declare var window: MyNamespacedWindow;
Upvotes: 17
Reputation: 591
Create a file called global.d.ts
, e.g., /src/@types/global.d.ts
, and then define an interface like:
interface Window {
myLib: any
}
Reference: Global .d.ts
Upvotes: 59
Reputation: 11714
For those who want to set a computed or dynamic property on the window
object, you'll find that not possible with the declare global
method. To clarify for this use case
window[DynamicObject.key] // Element implicitly has an 'any' type because type Window has no index signature
You might attempt to do something like this
declare global {
interface Window {
[DyanmicObject.key]: string; // error RIP
}
}
The above will error though. This is because in TypeScript, interfaces do not play well with computed properties and will throw an error like
A computed property name in an interface must directly refer to a built-in symbol
To get around this, you can go with the suggest of casting window
to <any>
so you can do
(window as any)[DynamicObject.key]
Upvotes: 8
Reputation: 4542
If you are using TypeScript 3.x, you may be able to omit the declare global
part in the other answers and instead just use:
interface Window {
someValue: string
another: boolean
}
This worked with me when using TypeScript 3.3, Webpack and TSLint.
Upvotes: 19
Reputation: 579
Make a custom interface that extends the Window and add your custom property as optional.
Then, let the customWindow use the custom interface, but valued with the original window.
It's worked with the TypeScript 3.1.3.
interface ICustomWindow extends Window {
MyNamespace?: any
}
const customWindow:ICustomWindow = window;
customWindow.MyNamespace = customWindow.MyNamespace {}
Upvotes: 8
Reputation: 21
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
extension 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.
Upvotes: 2
Reputation: 973
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';
Upvotes: 37
Reputation: 2759
Globals are "evil" :) I think the best way to also have the portability is:
First you export the interface: (for example, ./custom.window.ts)
export interface CustomWindow extends Window {
customAttribute: any;
}
Second, you import
import {CustomWindow} from './custom.window.ts';
Third, cast the global variable window with CustomWindow:
declare let window: CustomWindow;
In this way you also don't have a red line in a different IDE if you use it with existent attributes of the window object, so at the end try:
window.customAttribute = 'works';
window.location.href = '/works';
Tested with TypeScript 2.4.x and newest!
Upvotes: 143
Reputation: 4481
Most of the other answers are not perfect.
I also encountered a similar problem this morning. I tried so many "solutions" on Stack Overflow, but none of them produced absolutely no type errors and enabled triggering type jumping in the IDE (WebStorm or Visual Studio Code).
Finally, from Allow module definitions to be declared as global variables #3180
I found a reasonable solution to attach typings for a global variable that acts as interface/class and namespace both.
The example is below:
// typings.d.ts
declare interface Window {
myNamespace?: MyNamespace & typeof MyNamespace
}
declare interface MyNamespace {
somemethod?()
}
declare namespace MyNamespace {
// ...
}
The code above merges the typings of namespace MyNamespace
and interface MyNamespace
into the global variable myNamespace
(the property of window).
Upvotes: 50
Reputation: 3661
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
}
The same idea for Node.js:
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");
Upvotes: 8
Reputation: 834
After finding answers around, I think this page might be helpful:
I am 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 || {};
Upvotes: 23
Reputation: 8751
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 any more:
window.MyNamespace = window.MyNamespace || {};
Upvotes: 16
Reputation: 5554
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.
Upvotes: 71
Reputation: 35267
I just found the answer to this in another Stack Overflow 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.
Upvotes: 1565
Reputation: 1114
TypeScript does not perform typechecking on string properties.
window["newProperty"] = customObj;
Ideally, the global variable scenario should be avoided. I use it sometimes to debug an object in the browser console.
Upvotes: 17
Reputation: 4280
First you need to declare the window object in the current scope. Because TypeScript would like to know the type of the object. Since the window object is defined somewhere else, you can not redefine it.
But you can declare it as follows:
declare var window: any;
This will not redefine the window object nor will it create another variable with name window
. This means window is defined somewhere else and you are just referencing it in the current scope.
Then you can refer to your MyNamespace object simply by:
window.MyNamespace
Or you can set the new property on the window
object simply by:
window.MyNamespace = MyObject
And now the TypeScript won’t complain.
Upvotes: 12
Reputation: 9965
As of TypeScript ^3.4.3, this solution no longer works
Or...
you can just type:
window['MyNamespace']
And you won’t get a compile error and it works the same as typing window.MyNamespace
.
Upvotes: 234
Reputation: 6277
To keep it dynamic, just use:
(<any>window).MyNamespace
Note that this may not work with TSX because the compiler might think that the <any>
is a TSX element. Check out this answer for type assertion that is compatible with TSX.
Upvotes: 571
Reputation: 6601
Using Svelte or TSX? None of the other answers were working for me.
Here's what I did:
(window as any).MyNamespace
Upvotes: 312
Reputation: 654
Using create-react-app v3.3 I found the easiest way to achieve this was to extend the Window
type in the auto-generated react-app-env.d.ts
:
interface Window {
MyNamespace: any;
}
Upvotes: 18
Reputation: 2797
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.
Upvotes: 84