-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recognize JS namespace pattern in TS #37321
Comments
@sandersn thoughts? I feel like this is a pretty easy hack for detecting expando initializations |
How Hard Can It BeWell, Assuming that the binder could recognise uses of JavaScriptNamespace, supporting namespace declaration with it would be similar to support for Is It A Good IdeaI don't like the idea of introducing magic identifiers when there's any way around it. We introduced I think a good gauge of how desirable this feature is: how many code bases out there use it? How widely used are they? Scraping github for examples and relative popularity would help answer this question. Other Upgrade OptionsIt's a long shot, but could you generate code to declare a namespace with a function inside and expand the function with expando assignments? // generated code
declare namespace app.pages {
declare function admin(): void
}
// original assignment
namespace("app.pages.admin");
app.pages.admin.mailing = (function () {
return {
sendMail: function (email: string): void { }
}
})() |
Thank you guys for response! I was hoping that TS support some kind of "ambient expando object in nested namespace", and @sandersn workaround provides it. It just feels a bit hacky and would be great if Typescript support similar "expando" pattern on empty declare namespace app.pages {
const admin: {}
}
namespace("app.pages.admin");
app.pages.admin.mailing = (function () {
return {
sendMail: function (email: string): void { }
}
})() I also don't understand why it doesn't work with assigning just object literal (without wrapping in IIFE) declare namespace app.pages {
function admin(): void
}
namespace("app.pages.admin");
app.pages.admin.mailing = {
sendMail: function (email: string): void { }
} I got But it's not a big problem. This workaround is good enough and resolves most of my problems. |
I short, I propose two things:
--allowJs
. Likevar my = my || {}; my.app = my.app || {};
(can't navigate javascript with manual namespaces #7632)Ext.na("Company.data")
should have the same effect as writing it "by hand" withvar Company = Company || {}; Company.data = Company.data || {};
Why 1.
It's now possible to have project with
--allowJs
flag when you can define such code in JS file and TS file recognizes it:JS file:
TS file:
See what I get when I hover over
![image](https://user-images.githubusercontent.com/2056282/76325216-6209d380-62e7-11ea-944d-e6d3deb475e7.png)
mailing
property in my TS file.The problem is that I want to incrementally migrate old JavaScript project to Typescript and convert each JS file to TS. It's not so easy or obvious how to migrate JS file that use this namespaces pattern without adding a lot of type definitions that can be inferred in JS file with
allowJs
compiler flag. Why not recognize this pattern in Typescript files?Why 2. and example
This is the actual pattern that my current project uses in JS files
namespace
function is global function that basically creates global namespace objects. It's logically equivalent to writingvar app = app || {}; app.pages = app.pages || {}; app.pages.admin = app.pages.admin || {};
from previous example.I want to be able to change JS file to TS file and be able to use this code in new TS files (but with static safety that TS provides).
I propose that we recognize special type alias definition for which compiler will recognize this pattern and act as if this global "javascript namespace" (or "expando" object) was created. For example this type alias will be added to standard lib:
Then I could declare global
namespace
function like thisand this TS code would be valid:
It's a bit similar in spirit to
ThisType
. I mean compiler have special handling to some type. But if old compiler sees this type then nothing happens (it's just a string type).Use cases and current "workarounds"
It's all about making migration of current JS project to TS easier. It's hard to convince my team (and even myself) that we should use TS when you need to write code like this to get the same behavior you had in JS but with type safety:
you need to write type definitions for you methods twice and split you type definitions into interfaces to merge them 🤮
My current workaround is using Typescript namespaces like this (I have two approaches, don't like either of them):
There are many problems with this use of Typescript's namespace:
return
in IIFE. Something like that:But it's not supported. I guess it's not worth to change it now since namespaces are not used that often nowadays.
In the end I had to use different name that I would use in TS files and use workaround to make old name work in other JS files:
Summary
As I mentioned it's all about easing migration of old JavaScript projects that use old namespace pattern (for example because they use ExtJS library) to TypeScript. I know that nowadays this pattern is not that popular because you should use ES modules. But I believe there are a lot of people that would love to move their projects to TS but it's hard because it would require to move to ES modules first. And it's a huge task itself. Actually my plan is to migrate current code to TS with old namespace and then try to migrate it to ES modules. It should be much easier to migrate when most of you code is typed. You have more confidence when compiler helps you.
If TS team thinks that it's only worth doing 1. proposal (just recognize what's recognized in
allowJS
now, without implementingJavaScriptNamespace
alias proposal) it would be "good enough" for me because it will be much better than my current namespace workarounds.But if I had this
JavaScriptNamespace
alias feature then it would be possible to include all my JS files to TS compilation withallowJS
and this JS code will be available in TS! (of course function arguments will beany
, but still). I would also get better IntellSense in current JS files because thisnamespace
function will be recognized as creator of a namespace (when using Salsa).Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: