You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Variable usage issues caused by global Window object #1351
I figured out why this happens - and I think the TypeScript compiler needs, at the very least, a warning here.
Apparently, all the global Window properties are visible "as is" - which means that using them inside functions is automatically "resolved", even if their use is a typo or an error (as it was in my case).
If I may suggest, please add a warning when compiling .ts code that uses these "globals" - e.g.:
... bug.ts(6, 10): Warning: you are accessing the global 'window.name' here - to remove this warning, change 'name' to 'window.name'.
We don't actually add all the members of Window to the global namespace; name (and other globals) are just declared twice (once globally, once in the Window interface).
I am inclined to say we should remove the name and length properties from the global declaration space as they are very likely to be used intentionally. It would be a breaking change but I don't think people actually use those properties in an unqualified way (on purpose).
I am inclined to say we should remove the name and length properties from the global declaration space as they are very likely to be used intentionally.
👍
Other common sources of error include location, parent and event.
I've also had problems with document but that is likely to be used unqualified intentionally.
I don't think it should be removed. That would allow writing code like
varname=[1,2,3];// Expect name to be number[]name.forEach(...);// Blows upconsole.log(name==="1,2,3");// true - it's actually the string "1,2,3" because it does set window.name which stringifies the array
Edit: Or even with a string name, it'd give the false impression that it's a separate entity from window.name when it actually isn't.
I agree with Carl (@Seikho). ECMAScript is host-neutral. W3C specifies web APIs for standard browser hosts, The Node.js Foundation specifies the node.js host environment. I don't think either belong in the default lib.d.ts. Specifically lib.es5.d.ts, lib.es6.d.ts, etc bundle browser-side web APIs, even though they are not part of any version of the ECMA-262 standard.
The OP's problem arises because the default lib.d.ts declares all the Web APIs, thus treating all environments (including node.js ones) as if they are browser environments, which does not reflect the runtime reality. A node.js project written in TypeScript can reference all Web APIs, everything from name to requestAnimationFrame to HTMLCanvasElement, without a compiler error (but obviously with a runtime error). As TypeScript's type system becomes ever-more expressive and accurate, I think this approach looks increasingly 'loose' and unacceptable.
I'd prefer that the browser host environment was in a separate opt-inlib.web.d.ts (or similar), much the same as the node.js host environment is in a separate opt-in node.d.ts. That way, both browser and node.js projects may opt-in to their own host environment without any global pollution from the other environment.
The team recently decided not to bundle node.js typings. How about unbundling the web API typings too? That would make TypeScript host-neutral like ECMAScript is, and put node and browser projects on an equal footing.
Yui (@yuit) can you confirm Arnav Singh (@Arnavion)'s above comment? Looking at the diff for 6974, I can see that lib.d.ts still bundles in all the Web APIs, and I can't see any DOMWithoutGlobal option for lib.
How do I target, say, an ES6 node.js environment, without including all the browser-side typings?
Confirmed it myself. Adding "lib": ["es6"] to the project's tsconfig.json includes just the ECMA-262 definitions (Set, Map, Promise, etc) but none of the Web APIs (window, name, etc).
Adding "lib": ["es6", "dom"] includes both the ECMA-262 typings and the Web API typings.
So, is there any reason why this issue remains open? It seems no longer a problem. What other changes are needed?
EDIT I'd say discoverability is still an issue. tsc includes all Web APIs in the build by default, and you have to opt-out by specifying something like "lib": ["es6"], which is not obvious.
Troy Gerwien (@yortus) the "solution" to this thread is not the --lib option per se, because the "dom" option still pollutes the global namespace with variables like name (and others) (see this comment from @RyanCavanaugh)
However, we could argue that typing name as never is not sufficient.
As Ian Suda (@isuda) pointed out, the never fix won`t catch everything.
Basically, using never as "do not use" label is a misuse. never type stands for "never reach at runtime" or something.
Then, passing around never value will not be compile error ("never is a subtype of every type") because these code isn't thought to be executed.
So we can do better.
An optimal solution can be introducing another special type prohibited, which any usage of that type except variable declaration raises an error.
Activity
ttsiodras commentedon Dec 3, 2014
I figured out why this happens - and I think the TypeScript compiler needs, at the very least, a warning here.
Apparently, all the global Window properties are visible "as is" - which means that using them inside functions is automatically "resolved", even if their use is a typo or an error (as it was in my case).
If I may suggest, please add a warning when compiling .ts code that uses these "globals" - e.g.:
... bug.ts(6, 10): Warning: you are accessing the global 'window.name' here - to remove this warning, change 'name' to 'window.name'.
NoelAbrahams commentedon Dec 3, 2014
This is a common problem and it would be nice to have a solution.
See #494 and #983
RyanCavanaugh commentedon Dec 3, 2014
We don't actually add all the members of Window to the global namespace;
name(and other globals) are just declared twice (once globally, once in the Window interface).I am inclined to say we should remove the
nameandlengthproperties from the global declaration space as they are very likely to be used intentionally. It would be a breaking change but I don't think people actually use those properties in an unqualified way (on purpose).NoelAbrahams commentedon Dec 4, 2014
👍
Other common sources of error include
location,parentandevent.I've also had problems with
documentbut that is likely to be used unqualified intentionally.[-]Failure to detect use of non-existing variable...[/-][+]Variable usage issues caused by global Window object[/+]Arnavion commentedon May 28, 2015
I don't think it should be removed. That would allow writing code like
Edit: Or even with a string
name, it'd give the false impression that it's a separate entity from window.name when it actually isn't.33 remaining items
yortus commentedon Jun 27, 2016
I agree with Carl (@Seikho). ECMAScript is host-neutral. W3C specifies web APIs for standard browser hosts, The Node.js Foundation specifies the node.js host environment. I don't think either belong in the default
lib.d.ts. Specificallylib.es5.d.ts,lib.es6.d.ts, etc bundle browser-side web APIs, even though they are not part of any version of the ECMA-262 standard.The OP's problem arises because the default
lib.d.tsdeclares all the Web APIs, thus treating all environments (including node.js ones) as if they are browser environments, which does not reflect the runtime reality. A node.js project written in TypeScript can reference all Web APIs, everything fromnametorequestAnimationFrametoHTMLCanvasElement, without a compiler error (but obviously with a runtime error). As TypeScript's type system becomes ever-more expressive and accurate, I think this approach looks increasingly 'loose' and unacceptable.I'd prefer that the browser host environment was in a separate opt-in
lib.web.d.ts(or similar), much the same as the node.js host environment is in a separate opt-innode.d.ts. That way, both browser and node.js projects may opt-in to their own host environment without any global pollution from the other environment.The team recently decided not to bundle node.js typings. How about unbundling the web API typings too? That would make TypeScript host-neutral like ECMAScript is, and put node and browser projects on an equal footing.
Arnavion commentedon Jun 27, 2016
Carl (@Seikho) Troy Gerwien (@yortus) Note that as Zhengbo Li (@zhengbli) said, this problem is already solved for non-browser users with the
--libcompiler option.yortus commentedon Jun 27, 2016
Yui (@yuit) can you confirm Arnav Singh (@Arnavion)'s above comment? Looking at the diff for 6974, I can see that
lib.d.tsstill bundles in all the Web APIs, and I can't see anyDOMWithoutGlobaloption forlib.How do I target, say, an ES6 node.js environment, without including all the browser-side typings?
yortus commentedon Jun 27, 2016
Confirmed it myself. Adding
"lib": ["es6"]to the project'stsconfig.jsonincludes just the ECMA-262 definitions (Set,Map,Promise, etc) but none of the Web APIs (window,name, etc).Adding
"lib": ["es6", "dom"]includes both the ECMA-262 typings and the Web API typings.So, is there any reason why this issue remains open? It seems no longer a problem. What other changes are needed?
EDIT I'd say discoverability is still an issue.
tscincludes all Web APIs in the build by default, and you have to opt-out by specifying something like"lib": ["es6"], which is not obvious.myitcv commentedon Jun 27, 2016
Troy Gerwien (@yortus) the "solution" to this thread is not the
--liboption per se, because the"dom"option still pollutes the global namespace with variables likename(and others) (see this comment from @RyanCavanaugh)Avol-V commentedon Jul 6, 2016
And I once again draw attention to what is now the library has an error — property
eventthat is absent in the standard.lefb766 commentedon Aug 18, 2016
The problem with global 'name' is going to be fixed (#9850).
isuda commentedon Jan 9, 2017
Mohamed Hegazy (@mhegazy) - This issue as stated in the original post is not fixed.
I can still do
console.log(name);even if name is typenever.Even worse, I can now do stuff like this:
mhegazy commentedon Jan 9, 2017
namedoes exist in the global scope if you are using DOM. so we can not remove it totally.lefb766 commentedon Feb 5, 2017
Mohamed Hegazy (@mhegazy) I'm not sure what you meant by "remove it totally".
My understanding is that you are saying we cannot remove
nameand others from the global because people can still re-declare them to get runtime error.That's why #9850 was applied, wasn't it?
However, we could argue that typing
nameasneveris not sufficient.As Ian Suda (@isuda) pointed out, the
neverfix won`t catch everything.Basically, using
neveras "do not use" label is a misuse.nevertype stands for "never reach at runtime" or something.Then, passing around
nevervalue will not be compile error ("never is a subtype of every type") because these code isn't thought to be executed.So we can do better.
An optimal solution can be introducing another special type
prohibited, which any usage of that type except variable declaration raises an error.