Visual Studio 2017, JavaScript intellisense inconsistencies - javascript

TL;DR: How do you include a tsconfig.json file in Visual Studio 2017 and still have JavaScript intellisense work like it does by default, giving code hints both for your own code and 3rd-party libraries? Is it borked, or do I just need a better understanding of how it works?
Much like jQuery, I would like ubiquitous access to my own JavaScript namespaces across JavaScript and html files with intellisense. How does one achieve this?
EDIT 3:
I reported this issue on developercommunity.visualstudio.com. Please consider up-voting the issue to attract more attention from Microsoft.
EDIT 2:
Currently the "solution" is Resharper, which provides what one would expect straight out-of-the-box. But it's not really ideal at a price of $299/yr/user for something Visual Studio markets it provides itself.
EDIT 1:
In the event that my expectations for JavaScript intellisense in Visual Studio is inaccurate, below is a contrived example of how I expect it to function.
Say I create three TypeScript files in my ./Scripts folder, we'll call them A.ts, B.ts, and C.ts. Each will contain its own namespace:
A.ts
namespace A {
export function f1(s: string) {
return s;
}
}
B.ts
namespace B {
export function f1(n: number) {
return n;
}
}
C.ts
namespace C {
export function f1(b: boolean) {
return b;
}
}
At this point in time one may expect to be able to start seeing intellisense for their newly created namespaces, and indeed, within A.ts, B.ts, and C.ts you begin to see intellisense for those namespaces. Cool.
Unfortunately this doesn't carry over to other places, like /Home/Index.cshtml. Index.cshtml knows nothing about the A, B, or C namespaces. Additionally, .js files know nothing about these namespaces, hence the need for their respective TypeScript Declaration (.d.ts) files.
So we'll go ahead and add our tsconfig.json file to the root of our project and configure it like we do above. If we perform an edit on one of our .ts files and save it, this triggers the compilation of our corresponding .d.ts files into our ./Scripts/out folder. Do we now get intellisense in Index.cshtml and .js files? ...No.
Now you might be thinking these files need to be included in the project in order for Visual Studio to pick them up for intellisense (they're excluded on creation). So you include them in the project. Intellisense? No. jQuery intellisense? No. Perhaps they need to be in the same directory as the file you want to use them in? .....Kind of? I've ran into intellisense being inconsistent like this on a number of occassions:
Somehow we're getting intellisense for our 'A' namespace within our C3.js (note: a JavaScript file), but none of the other ones. What?
Perhaps you think you're on the right track and that you've scored a small victory against the intellisense engine. But then you restart your Visual Studio instance and...
Wait....I just had intellisense for the 'A' namespace. What happened!?
I have no idea. But after messing around for a bit I try placing an import statement at the top of the .js file, and all of a sudden intellisense starts kicking in for the imported files/modules. Huzzah!
And even in Index.cshtml I begin receiving intellisense for our imported namespaces.
The moment I close the .js file with the import statements, though, all of a sudden I lose the intellisense for them in Index.cshtml. Wait...what?? And unlike in JavaScript files, I'm unable to write an import statement to receive intellisense for them:
Or at least... not with my own namespaces:
It's this inconsistent back-and-forth that confuses the heck out of me as to how exactly Visual Studio's JavaScript intellisense actually works. I still don't know if it's just broken or if I need a better understanding of it.
ORIGINAL POST
System
Windows 10VS2017 15.0.0+26228.10New JavaScript language service is enabled
I've been fighting to get Visual Studio 2017's JavaScript intellisense to work for me for a couple of days now to no avail. I don't know if something's genuinely wonky with the IDE or if I just don't understand it properly.
My understanding of how VS2017's JS intellisense works is now by typescript definition files, or .d.ts files. Ultimately I would like to get intellisense to help us out with our own TypeScript/JavaScript but right now I'd settle for just having it work consistently within a fresh project.
If I create a new ASP.NET MVC 4.5.2 project, out-of-the-box JS intellisense seems to work fine, and by that I mean I can type a dollar sign ($) either in a .js file or between <script> tags and I properly receive intellisense for jQuery. Awesome. Now, with the ultimate goal in mind of creating TypeScript files (.ts) and having the TypeScript compiler generate our .d.ts files automagically so that we can get rich intellisense for our own code, I wish to introduce a tsconfig.json file to the root of the project in order to configure that.
After creating the tsconfig.json file JS intellisense ceases to function. I type a dollar sign ($) into either a .js file or between <script> tags and I get zero intellisense for jQuery. This was a frustrating experience for a while but then I read this little note found on the linked page above:
NOTE: This feature is disabled by default if using a tsconfig.json
configuration file, but may be set to enabled as outlined further
below).
"This feature" is in reference to "By default, the Salsa language service will try to detect which JavaScript libraries are in use...in order to provide richer IntelliSense." Ok, so the Salsa language service will not autodetect libraries in use and provide intellisense for them when a tsconfig.json file is present, unless you specifically configure it to do so as "outlined below." At least, that's how I understand it.
If we scroll down the page a little bit and come to the tsconfig file settings we come across a setting for enableAutoDiscovery which "enables the automatic detection and download of definition files as outlined above." It's not super explicit as to what "as outlined above" is in reference to, but I can only assume it's in reference to the previous note indicative of re-enabling Salsa's auto-detection feature to provide rich intellisense. So I include that option in my tsconfig.json file and...no benefit; still no JS intellisense.
As it turns out, typingOptions.enableAutoDiscovery has been renamed to typeAcquisition.enable. Grrrrr. Alright, so we make that change in our tsconfig.json aaaaaaand... still no JS intellisense.
At this point I am able to write my own .d.ts files and Visual Studio's intellisense will pick it up alright (most of the time...), but I still have no intellisense for 3rd-party libraries like jQuery, which is no good.
So far I've landed on the following tsconfig.json file:
{
"compilerOptions": {
"noEmitOnError": true,
"noImplicitAny": false,
"removeComments": false,
"target": "es5",
"declaration": true,
"declarationDir": "./Scripts/out"
},
"compileOnSave": true,
"typeAcquisition": {
"enable": true,
"include": ["jquery"]
},
"include": [
"./Scripts/app/**/*"
],
"exclude": [
"./Scripts/vendors/**/*",
"./Scripts/out/**/*"
]
}
With the TypeScript virtual project in view I can see that my project's .ts files are included as well as jQuery in my %LOCALAPPDATA%\Microsoft\TypeScript\node_modules#types directory.
I was hopeful that with all this in place I would have both intellisense for my own project's .ts files and 3rd-party libraries (at least those specifically included; jQuery only at this point). Alas...no. Still no jQuery intellisense.
Incidentally, if I write an import line for jQuery, all of a sudden I get jQuery intellisense
...interesting. And maybe that makes perfect sense; I haven't messed a whole lot with module imports and how Visual Studio's intellisense handles those, but what I really want is to have intellisense application-wide for both our code and 3rd-party libraries.

JS files are for javascript and are not transpiled using the typescript compiler.
If you are using typescript then keep all your typescript in ts files.
Also, you shouldn't put typescript inside your cshtml files because typescript is not javascript. You need to use the typescript compiler to transpile your typescript into javascript which you can then use that javascript inside your HTML pages.
I think what you are trying to do is not a way typically how people use typescript. Usually you write all your typescript in TS files and then as a build process you transpile all your typescript into javascript. There are many strategies on how to do this. You can bundle all your javascript into one file or break them up into modules. There is a lot of options on how you want your final javascript output to look.
Your CSHTML views would reference your compiled javascript and not your typescript. The browser doesn't know what to do w/ typescript.

It looks like the latest update March 14, 2017 (build 26228.09) caused this issue, you can go to Control Panel—Programs and Features-View Installed updates and remove this update, then reopen VS to check the intellisense. If it works, which means this update lead to this issue, you can temporarily not install this updat
I've noticed the Microsoft Report Projects for Visual Studio Extension can cause problems such as this when being used in a project, A couple of mine have broken right after I add my SQL Server Report project to the solution and restarted visual studio.. So for now I remove my Report project from the solution but I hope Microsoft fixes this issue

Related

How to use npm packages as ES6 modules loaded by the browser in 2021?

I'm a JavaScript beginner. I do not use a "bundler".
For a few days now I've been trying to use moment.js and other date-time libraries in some JavaScript by importing it using ES6 modules (ESM).
I have a JS module I wrote, which is transpiled from TS, and that has this line:
import moment from "../lib/moment/src/moment.js"
My module is itself loaded via an import from a <script type="module" > tag, which works.
I've discovered that the moment package contains what looks like "source" code in its src folder which seems to look more like the JS/TS I'm accustomed to, and has a "default export" at the bottom.
So I'm referencing that "source" version in my transpiled JS module. This gets me past a couple of errors I was getting:
The requested module 'blah' does not provide an export named 'default'
And
Cannot set property 'moment' of undefined (at moment.js:10)
And leaves me stuck with loading the other modules its dependent upon, because I guess, their file extensions are missing.
GET https://blah/lib/moment/src/lib/locale/locale net::ERR_ABORTED 404 (moment.js:37)
After 3 days tearing my hair out I feel like I have been fighting a battle I shouldn't be attempting at all.
I would expect in 2021, what with widespread ESM browser support, that this would just work, but I've tried 5 different date-time libraries and had no success.
I assume the 404s have occurred because the moment authors are NOT expecting people to be using their library like this, so they left off the file extensions knowing full well that it wouldn't load in a browser??
Am I supposed to add an extra step in my client-side build process, Gulp, to add the extensions back on in the moment source code??
Or am I doing something else wrong?
Is it perhaps that everyone uses a "bundler" and these tools fix all this stuff somehow and so these issues never arise for 99% of web devs??
Thanks in advance.
You want to import a bundled version of the lib to be able to do that. Try:
import from 'https://unpkg.com/moment#2.29.1/dist/moment.js' ;
You can download the bundled version and add to your project. Don't forget to put the license as well and check if they are at least MIT or similar.
If you want to refer to the source code you will certainly need to build that. Specifically with libs that are using typescript.

Typescript - migrating JS code with strict flags

I'm starting to migrate a large JS codebase into TS.
As recommended in the Migrating from JavaScript document, I started by setting the tsconfig.json file to allowJs: true.
The migration procedure is that whenever I add a new file to the codebase, I add it in TS.
Since I want to be as strict as possible for these new TS files, I've added the different strictness options in the tsconfig.json file such as "noImplicitAny": true, "noImplicitThis": true.
Thing is, once I do so I get a ton of errors for all of my non-migrated JS files that, of course, lack typings for different arguments and therefore have an implicit any type.
What is the suggested workflow in this condition?
As described above, I want to:
Be as strict as possible for the new TS files I create.
Run TS standard checks on my JS files, e.g. unreached code or unused variables.
Not having the same TS strictness on my JS files as it will simply mean I need to migrate all of my code to TS straightaway, which is not really feasible.
Is it somehow possible with different tsconfig.json files for JS and TS files?
What is the best practice here?
Edit:
As Matt mentioned in the comment below, I was indeed using the checkJs: true flag which is what caused the compiling errors in the JS files.
I understood that even without porting your JS files to TS, you receive "out-of-the-box" type checking even when you use .js files, but that isn't happening for me.
Without the checkJs flag, I receive Unreachable code detected and 'x' is declared but is never used warnings, but that seems to be it.
For some reason, I was sure that it will also catch stuff like the following:
let num = 12;
num = "aa";
But it doesn't depict any warnings (and the intellisense doesn't "know" that num is of type number).
When reading the Migrating from JavaScript article again (the "Early Benefits" section), I can see that it indeed states that all I get is a very limited typing check support.
So last thing before I close this question - is this somehow configurable or that's it?
You will indeed have to use two tsconfig.json files, one with "noImplicitAny": true (and any similar options) but not "checkJs": true and the other with "checkJs": true but not "noImplicitAny": true. It should be straightforward to get your build system to run tsc once on each tsconfig.json file and show all the errors. You'll probably want to set "noEmit": true in one of the two files. (If you need help with this, let me know.)
If you are using Visual Studio Code as your IDE, then based on my brief tests, there doesn't seem to be a way to get Visual Studio Code's TypeScript language service (used for error reporting as you edit) to apply different tsconfig.json files to your TypeScript and JavaScript source files (unless you can separate the files into two folders with dependencies going in only one direction, which doesn't appear to be your scenario). So you'll have to pick one of the two configurations as your main configuration and refer to the build output for the errors detected only by the other configuration. (I can't speak for other IDEs.)

In the Angular4 Webpack Starter, does tsconfig.webpack.json work for webpack while tsconfig.json works for everything else?

Please refer to this git repository: https://github.com/AngularClass/angular-starter
The Angular4 Webpack Starter comes with 2 files:
tsconfig.json
and
tsconfig.webpack.json
Each file has slightly different configurations for TypeScript.
My question is regarding how these 2 files work in relation to the project.
Will the tsconfig.webpack.json only be applied to the ts-loader used by Webpack? while the tsconfig.json file will apply to everything else?
Any information on what tsconfig.webpack.json would be greatly appreciated.
The short answer is yes. The TypeScript loader registered with Webpack is explicitly configured to use the tsconfig.webpack.json file. This can be observed on line 133 of the common configuration.
The tsconfig.json file is there for IDE support.
It is worth noting that, while you state that the template uses ts-loader, it actually uses awesome-typescript-loader.
Having said that, both loaders will by default try to pick up a file named tsconfig.json and that the template is explicitly overriding this behavior on the linked line.
While there are multiple reasons why one might want to use more than one TypeScript script configuration file in a project, editors, such as Visual Studio Code, use the one named tsconfig.json to power features such as intellisense, set various options, and to determine the extent of a project.
It is more than reasonable to use the same file for both and that is actually what would happen by default.
Remarks
Please note that the AngularClass template is extremely bloated and complicated. Considering it is meant as a starting point, which you will no doubt add to, the amount of unnecessary boilerplate and cruft that you start out with by basing your application on such a template should be taken into very serious consideration. This goes double if you are new to any of the tools, transpilers, or frameworks involved.
By the way, I'm actually a contributor to that repository. They took a pull request from me that changed a utility function which someone filed an issue for as being confusing. The funny thing was that I had removed that very function from our project long before I submitted the PR improving it.
Having worked on a project which was derived from one of their templates, I wasted a lot of time ripping out Webpack config related code that was not needed but was getting in the way. We ended up with only a ~hundred lines of Webpack config total. I wasn't, and still am not a huge Webpack fan (JSPM for the win), but Webpack was not being utilized well by the template. Lots of unnecessary work was being done which actually made Webpack seem more complicated than it is. That entire helpers file is basically worthless and none of it had anything to do with Webback, or TypeScript, or even Angular.
This is also a bit troubling since the angular class website sells training material. There's nothing wrong with that in principle or in practice, but they create a lot of complexity in addition to what is inherent in an already complex tool chain.
Will the tsconfig.webpack.json only be applied to the ts-loader used
by Webpack?
Yes, that is correct. Here is where the tsconfig.webpack.json is used in webpack.common.js:
new ngcWebpack.NgcWebpackPlugin({
...
disabled: !AOT,
tsConfig: helpers.root('tsconfig.webpack.json'), <----------------
}),
and for awesome-typescript-loader here:
{
loader: 'awesome-typescript-loader',
options: {
configFileName: 'tsconfig.webpack.json', <-------------------
useCache: !isProd
}
},
while the tsconfig.json file will apply to everything else?
Yes, it's used for tslinting or if you need to produce declaration files. If you're working in IDE it can also be used for intellisense and other IDE specific functionality.

How export and import work in typescript?

I was going through Angular2 quickstart tutorial with Javascript and Typescript as well, In javascript version I observed that components and modules are first assigned to a variable (window.app which I understood as some global variable that can be accessed across js files or script blocks) and that is fine. Coming to type script version just export and import were used, I tried to analyze the generated javascript code but understood nothing. Can some one explain me how this export and import works in Tyepescript.
Import and export in typescript are explained well by the documentation here https://www.typescriptlang.org/docs/handbook/modules.html.
Like toskv said in his comment, how those statements in your TypeScript files get transpiled into statements in your JavaScript files depends largely on the module system you set up in your tsconfig.json file.
For example, setting "module": "commonjs" will cause the TypeScript compiler (tsc) to transform your import/export statements into essentially node.js-style require() statements. This documentation has a few simple, but helpful, examples of how node.js modules work: https://nodejs.org/api/modules.html.
Using a setting of "systemjs" instead of "commonjs" will make TypeScript translate your import/export statements into a format that SystemJS understands, of which I am no expert.
This process is further complicated by the fact that Angular 2 projects also require build steps that take the transpiled JavaScript files and turn them into packaged "bundles." These bundled files are (depending on your configuration settings) concatenated, minified, and perhaps even uglified. So looking at the final javascript code that is run is really not helpful, as it was not written by humans.
For example, the Webpack build system (google webpack.js) takes require() statements it finds in JavaScript code and does some magic to wrap each module in its own __webpack_require__ function, which allows the build system to take your whole project file structure and bundle it in to one or several JavaScript files which still maintain their dependencies on each other.
In other words, by the time you look at the production JavaScript code, it's not meant to be intelligible by human readers. The flow can be simply represented by TS Source Code > TS Transpilation into JS Code > Module/Dependency Build Steps into Production JS Code.
TL;DR TypeScript doesn't actually handle the module importing/exporting. During transpilation, it converts those statements into statements other module systems (node.js or SystemJS) can understand, which are in turn converted into production code for serving an Angular 2 application.

TSLint on javascript files

I spent many hour getting this to work, still without success...
The question is: How to use the TSLint on .js file?
Why? I'm trying to have best possible IDE for writing many JavaScript scripts, used in our internal SW.
My vision:
I have well documented TypeScript definitions of functions and want to use them in .js.
I want to import .js file and see the errors on it. TSLint is capable to do type control on .ts, according to .d.ts files. But on .js file, JSHint/ESLint can only see the function names and parametres from .d.ts files. Ok, but it's not enough. There is no type control in .js, which I'm missing.
Use JSHint/ESLint with TSLint in the same time. Using only few functions from both, but making great combo in the end. (TSLint for types, JSHint/ESLint for the rest)
Do not allow to use TypeScript keywords in JavaScript.
Autocomplete in .js from .d.ts. Ok, this is working.
I can code in VSCode, Sublime, NetBeans.
Thank you for an ideas!

Categories

Resources