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
Allow a union of libraries, for code that runs in multiple environmentsΒ #52433
TypeScript is fine with this if you include both 'DOM' and 'webworker' libs, but this code will fail in a webworker, because localStorage doesn't exist, and it will fail in a page, because importScripts doesn't exist.
This would be solved by a feature that allows developers to specify the environment as A or B. The code above would show errors, because localStoage and importScripts may not exist.
Having to switch configs is a bad developer experience here. Although, if the editor performed the checking with multiple configs and presented a union of the errors, that might satisfy this feature request.
Although, a single config that knows that the types are DOM or webworker would be faster than running two checks.
To take the example a bit further, imagine wanting to write this and tell developers it is safe to run in both workers and normal scripts:
if ("localStorage" in globalThis) {
localStorage.set('foo', 'bar');
}
This should compile. localStorage doesn't exist in a worker, but this code is fine because of the condition check.
Right now, for this code to build you have to include the DOM library. But as soon as you do that, TypeScript will happily let you remove the condition and write potentially unsafe code!
The problem we've had here in the past is that a huge amount of code can be seen to be running in one environment by inspection, but not in a way that's susceptible to static analysis. An example would be something like writing
This code is obviously fine, but TS would think that window and localStorage are possibly-not-present because there's no linkage between one DOM thing being present and everything else.
There's nothing today stopping someone from auto-genning variant DOM/webworker/etc libraries with every top-level declaration marked possibly-undefined. Real-world usage of such output would be good evidence that this kind of feature would be usable in practice.
Ryan Cavanaugh (@RyanCavanaugh) in those cases, I think it's reasonable to put a type guard on the global object, then access the APIs via the global object.
Although, typescript could be smart and realise that if the type of globalThis is guarded, global access could reflect that.
functionglobalIsWindow(global: any): global is Window{return'document'inglobal;}if(globalIsWindow(self)){self.addEventListener("click",()=>{self.localStorage.set("foo","bar");});}
But if TypeScript could determine that self represents the global-this, then:
Something like #50424 would make it a lot easier to create these kinds of isomorphic type guards, without needing to fork global type libs as Ryan Cavanaugh (@RyanCavanaugh) suggests.
Activity
MartinJohns commentedon Jan 26, 2023
You can already have multiple tsconfig and change them in VSCode (or editor of your choice). Otherwise it sounds like a duplicate of #37884.
jakearchibald commentedon Jan 26, 2023
Having to switch configs is a bad developer experience here. Although, if the editor performed the checking with multiple configs and presented a union of the errors, that might satisfy this feature request.
Although, a single config that knows that the types are
DOMorwebworkerwould be faster than running two checks.oliverdunk commentedon Jan 26, 2023
To take the example a bit further, imagine wanting to write this and tell developers it is safe to run in both workers and normal scripts:
This should compile.
localStoragedoesn't exist in a worker, but this code is fine because of the condition check.Right now, for this code to build you have to include the
DOMlibrary. But as soon as you do that, TypeScript will happily let you remove the condition and write potentially unsafe code!RyanCavanaugh commentedon Jan 26, 2023
The problem we've had here in the past is that a huge amount of code can be seen to be running in one environment by inspection, but not in a way that's susceptible to static analysis. An example would be something like writing
This code is obviously fine, but TS would think that
windowandlocalStorageare possibly-not-present because there's no linkage between one DOM thing being present and everything else.There's nothing today stopping someone from auto-genning variant DOM/webworker/etc libraries with every top-level declaration marked possibly-
undefined. Real-world usage of such output would be good evidence that this kind of feature would be usable in practice.jakearchibald commentedon Jan 26, 2023
Ryan Cavanaugh (@RyanCavanaugh) in those cases, I think it's reasonable to put a type guard on the global object, then access the APIs via the global object.
Although, typescript could be smart and realise that if the type of
globalThisis guarded, global access could reflect that.jakearchibald commentedon Jan 27, 2023
As in:
But if TypeScript could determine that
selfrepresents the global-this, then:if (globalIsWindow(self)) { - self.addEventListener("click", () => { + addEventListener("click", () => { - self.localStorage.set("foo", "bar"); + localStorage.set("foo", "bar"); }); }davidbarratt commentedon Jul 7, 2023
Perhaps this is what Jake Archibald (@jakearchibald) is saying, but I noticed that predicates on
globalThisdon't work:https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABDAzgdRmAJnA7gCkwAcQoAuRcAazDzAEoLjTkVENs9EBvAKEUQAnAKZQQgpFACeRYXGDIwJKIgC86xAHI4AIwBWw6JsQAyE4uWIAhBrAgANvdPnNOCCAC2wsFGOYLpADcvAC+vLwwCvhWqBw4BADm9roAhvYAKgAWqPT0PPyISakZ2SgAdG6e3lBlKVhYAKIAbtUAMqhQ3sKC+JrAcO4omgA0iPh5qgB8+QUh9MEhQA
If that could work, then it could be simplified to something like this:
where global keywords can be used in predicates.
robbiespeed commentedon Jul 7, 2023
Something like #50424 would make it a lot easier to create these kinds of isomorphic type guards, without needing to fork global type libs as Ryan Cavanaugh (@RyanCavanaugh) suggests.