Repository navigation
Expose global declarations on window #19816
Description
Window in a web page serves a dual purpose. it implements the Window interface representing the web page main view, but also acts as an alias to the global namespace. All global variables are accessible on the window object at run-time; this applies to builtin JS declarations like Array, Math, JSON, Intl as well as global DOM declarations like HTMLElement, Event, HTMLCollection, etc...
TypeScript today does not model this behavior. For instance window.Math is not defined, so is all the HTMLElement family of declarations.
Most of the patterns window is used to access global declarations are anti-patterns (see a good article about window usage), the main exception is testing for API existence, e.g.: if (window.MutationObserver) { ... }. There is not really a legal way to do this out-of-the-box in TS today.
Our recommendation has been to manually add a declaration for the global object on Window, e.g.:
declare global {
interface Window {
MutationObserver?: typeof MutationObserver;
}
}This is a. inconvenient and b. not easy to find if you are new to TS. Here is a list of issues we have so far related to this issue:
- Blob property is missing on Window interface #8866
window.Blob - ImageBitmap interface missing #14402
window.createImageBitmap - Property Math is missing on Window interface #9325
window.Math - URL is missing from Window interface #3753
window.URL - MutationObserver API declarations missing #11305
window.MutationObserver - window.PointerEvent is undefined #18756
window.PointerEvent - Event types do not exist in the Window interface #19758
window.MouseEvent - window.Element is a stable API, but is not included in the interface Window(lib.d.ts:19060). #23886
window.Element - Add typings for PerformanceObserver #25651
window.PerformanceObserver
It is also worth noting that the same problem occurs with self in web workers and global for node
Possible options here:
- support a global type (tracked by Access
globalas a type #14052), and allowWindowto extend from it. - generate lib.d.ts with all global declarations mirrored on
Window.
Activity
[-]Expose global declaration on `window`[/-][+]Expose global declarations on `window`[/+]yortus commentedon Nov 8, 2017
Can I bring up a third option? I think option 1 is the more flexible way of reducing duplicate declarations. However both options 1 & 2 have limitations:
supporting a global type and having
Windowextend it is pretty good because it is simple, and other environments (egGlobalinnode.d.ts) can use this too. But it would not solve the duplication problem in custom sandboxed environments, whereas the equally simple option 3 (below) would solve it.generating
lib.d.tswith all globals mirrored onWindow- but then do other environments miss out?node.d.tshas similar duplication of declared globals with theGlobalinterface, and then there are web workers, custom environments, etc.A third option would be a declaration that tells the compiler to augment the global environment with all the declarations in a particular interface. Eg
declare global extends Windowforlib.d.ts,declare global extends Globalfornode.d.ts, etc.This is similar to option 1 but in reverse, and allows additional scenarios like sandboxing. An example of this scenario is given in #10050 (comment). Note that if option 1 was used, then there would be no way to write a set of declarations that are just a normal interface in the host code but are are globals in the sandboxed code. They would all still have to be duplicated.
Custom environments may be niche, but it would be nice if the mechanism chosen here would work for them too.
Fix DefinitelyTyped#21235: add global types to DOMWindow interface
Fix DefinitelyTyped#21235: add global types to DOMWindow interface
michahell commentedon Apr 9, 2018
window.Worker, same story...HolgerJeromin commentedon Jul 23, 2018
One other valid usecase is if you are working with different contexts. For example we could be in another DOM (inside an
HTMLObjectElement) soSVGElementis a different one:mpawelski commentedon Apr 11, 2019
I just hit on this when I tried to migrate js library that uses a lot of
if(windows.Something)test.I though that it should be fixed in TS 3.4 after #29332
However I see that
windowis still declared asdeclare var window: Window;not asWindow & typeof globalThisas described in globalThis PR. Nathan Shively-Sanders (@sandersn) Are there plans to change it?sandersn commentedon Apr 15, 2019
Mariusz Pawelski (@mpawelski) Yes, by 3.5. I just haven't had a chance yet.
thomaLV commentedon May 30, 2019
What is the status on this?
maksnester commentedon Jul 5, 2019
Hey guys, so eventually, how nowadays with "typescript": "3.4.5" I can declare that inside window object, I have some variable with some type?
E.g. I have window.foo = { bar: 'baz' }, how I can declare it? Old way of doing that, I mean
is now produces this error
UPD: it looks like just adding a record in some d.ts file is ok. Like this:
But as I understood in such case I can't import some types in that file and use them in declaration, instead of
stringfor example. So what if I want to do something like that:?
inoyakaigor commentedon Aug 20, 2019
alendorff just to clarify: you had TS2669… error inside global.d.ts or index.d.ts?
maksnester commentedon Aug 22, 2019
Igor «InoY» Zviagintsev (@inoyakaigor) sorry, didn't understand your question, what's the difference between these 2 files if both are .d.ts ? I've not mentioned any specific filenames or something like that.
inoyakaigor commentedon Aug 22, 2019
alendorff I had the same TS2669 error for the code inside global.d.ts and I'm trying to figure out if the file name is relevant to this error. That's why I'm asking about the file name
maksnester commentedon Aug 22, 2019
Igor «InoY» Zviagintsev (@inoyakaigor) I don't have global.d.ts so filename is irrelevant I think
TranquilMarmot commentedon Jun 7, 2020
For anyone else landing here from a search, the following works to define new things on
windowand will get rid ofAugmentations for the global scope can only be directly nested in external modules or ambient module declarations. ts(2669):mersanuzun commentedon Jun 9, 2020
I want the dynamic key in window object. How can I do this? For example
window.lastNameorwindow.surnameCan I do this?
raphael10-collab commentedon Feb 9, 2021
Nate Moore (@TranquilMarmot)
In a Electron-React-Typescript app I'm getting this error:
Property 'api' does not exist on type 'Window & typeof globalThis'. window.api.send('open-type-A-window', '');But in a file index.d.ts I declared interface Window in this way:
What should I add / modify in order to avoid this error
Property 'api' does not exist on type 'Window & typeof globalThis'?TranquilMarmot commentedon Feb 9, 2021
raphael10-collab I don't think you need the
namespace NodeJS?raphael10-collab commentedon Feb 9, 2021
Nate Moore (@TranquilMarmot)
I tried also without NodeJS :
index.d.ts :
but still get this error:
in /src/App.tsx :
TranquilMarmot commentedon Feb 9, 2021
raphael10-collab you have a typo:
needs to be...
Also, I'm not sure you can implement code in a
.d.tsfile like that. It is only meant for declaring types.You should have a separate file that does something like this...
raphael10-collab commentedon Feb 9, 2021
After removing that typo: "api", { --------> "api": {
the problem persists.
So, may be it is like you say, that I have to define window.api = {} in a separate file.
But how to make it global? And in what kind of separate file? Any file?
I tried to put it into main.ts :
But still this error:
TS2339: Property 'api' does not exist on type 'Window & typeof globalThis'.TranquilMarmot commentedon Feb 9, 2021
raphael10-collab
You will need to put it in a file and then import that file into your application somewhere (the best spot may be in your main application file, something like
app.tsx?)You will also still need the
.d.tsfile (I would suggest calling itwindow.d.ts) to declare the types that are onwindow. It will look something like this but with your types:raphael10-collab commentedon Feb 9, 2021
Nate Moore (@TranquilMarmot)
I created two files:
window.ts :
And imported window.ts in main.ts and in src/components/App.tsx because of Electron apps added complexity of having two processes: main process and the renderer process.
The number of errors is now half: from 15 to 8.
But still have this kind of errors:
Found 8 errors.
I've put all the code in github repo, easier to look at : https://github.com/raphael10-collab/Libp2pPlaying
TranquilMarmot commentedon Feb 9, 2021
raphael10-collab I opened a PR against your repo, I hope it is helpful!
raphael10-collab commentedon Feb 9, 2021
Thank you very much Nate Moore (@TranquilMarmot)
There were and, unfortunately, there are a lot of errors.
I still have the same "Property 'api' does not exist on type 'Window & typeof globalThis'.
There must be a root cause to fix
68 ipcRenderer.removeAllListeners(channel);
~~~~~~~~~~~
TranquilMarmot commentedon Feb 9, 2021
It works for me using the code I have in my PR against your branch. You might have better luck asking about something like this on Stack overflow! Good luck!