Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript in Visual Studio 2017: Automatic definition inclusion causes Duplicate Identifier errors

UPDATE: I've got a workaround that makes things work acceptably with no hacks. I leave my prior attempts described below for posterity. See the answer for the working solution.


I've just upgraded an project to Visual Studio 2017 and I'm getting all kinds of TypeScript errors all of the sudden. Many of them are Duplicate identifier errors. When I double-click one of the errors, it opens a file called index.d.ts, located in a directory such as:

C:\Users\[me]\AppData\Local\Microsoft\TypeScript\node_modules\@types\jquery\index.d.ts 

Based on what I read on this page:

https://blogs.msdn.microsoft.com/visualstudio/2016/11/28/more-productive-javascript-in-visual-studio-2017-rc/

...it seems that what is happening is that Visual Studio is trying to helpfully download definition files for types where I've already manually included the definition files. The automatic inclusion of definition files sounds like a great feature! I'll just delete the manually included ones, right? But nothing I do seems to work. I hope someone can tell me where I'm going wrong.

For background, the way I had things working in Visual Studio 2015 was as follows. I was making use of three libraries: jQuery, jQuery UI, and QUnit. I simply downloaded the .d.ts files from DefinitelyTyped and put them in my Scripts directory in my project, and everything worked properly until I opened the project in VS 2017.

From the error messages, it seems that Visual Studio 2017 is bringing in its own definition files, so I figured I'd just delete the ones I had brought in manually. However, when I do that, now I get tons of Cannot find name $ errors, which seems to mean that those definition files are no longer being brought in for some reason.

Next, I figured that maybe the problem was that I didn't actually have the JQuery (and other library) source files in my project. I'm just referencing them from Google's CDN in my HTML source. The link above makes it sound like Visual Studio is looking for an actual loose file as the indicator that it should bring in definition files. So I manually added files to my Scripts directory and rebuilt, but nothing changed.

The linked page above also talks about including your library files from npm or bower, or using a tsconfig.json file, but before I go down those roads (not part of my normal workflow), I'm hoping someone can tell me, is there a preferred way of bringing in TypeScript definitions in Visual Studio 2017? Thanks in advance.


UPDATE: (See Update 2 below too) I was able to get things working. This was not exactly intuitive, so I'm sharing my steps here in the hope that a) it helps someone, and b) someone can tell me if I'm just doing this the wrong way.

  1. Remove all TypeScript code and definition files from project.
  2. Open packages.json and remove any definition file references there too.
  3. Clean and build. No errors or warnings.
  4. Via NuGet, install the definition file you need (for example, for jQuery, the package you want is "jquery.TypeScript.DefinitelyTyped").
  5. This will install the definition file in Scripts\typings\jquery.
  6. Do the same for other libraries you reference.
  7. Add a new test TypeScript file and add a line that attempts to utilize a library, for example, var foo = $(document);
  8. IntelliSense works! Project builds! Looks like we are back in business!
  9. Not so fast. A few seconds later, we're getting Duplicate identifier errors again. It seems that Visual Studio picked up the definition files on its own (perhaps activated by my inclusion of the definition files via NuGet) and now we have conflicts again.
  10. Add tsconfig.js file with the following directive, which prevents Visual Studio from downloading its own copies of the definition files: { "compilerOptions": { "types": [] } }
  11. Errors gone.
  12. Not so fast! Seconds later, hundreds of new errors appear, referencing TypeScript files that I have completely removed from my project. Opening one of the files referenced in the error window, it appears that copies were made in <Project>\obj\Debug\... (path was longer but I forgot to record it)
  13. No amount of cleaning the solution gets rid of these files.
  14. Delete the entire obj directory manually.
  15. Add all my original TypeScript files back into the project.
  16. Rebuild. Success!

UPDATE 2: I discovered some shortcomings with the approach above. I also have a better solution.

Using tsconfig.json has a major disadvantage. The option to recompile on save doesn't work within Visual Studio. I want to have my site running in debug mode, make some changes to the TypeScript, hit save, and then immediately see those changes reflected in the site.

I think one of the things that was causing trouble for me was that I have my TypeScript files in a folder other than Scripts, which I reserve for files that should be deployed to the server as-is. I guess Microsoft considers this a non-standard use case.

After banging my head against the wall for way too long over this, I've found a simple, though hacky, solution. I took all the subdirectories in this directory:

C:\Users\[me]\AppData\Local\Microsoft\TypeScript\node_modules\@types 

and moved them to a directory called Deleted.

Bam. No more automatic inclusion of definitions, no more errors.

Microsoft, if you're reading, please provide support for my scenario, which, to reiterate is:

  • TypeScript files stored in directory other than Scripts
  • Libraries (such as jQuery) included via reference to third-party CDN
  • Definition files for above libraries included directly via NuGet.

UPDATE 3: I finally got it working. See the answer below for a non-hacky solution.

like image 740
Brian Rak Avatar asked Mar 08 '17 04:03

Brian Rak


2 Answers

I got it working with no hacks. The trick is to use a tsconfig.json file and disable automatic definition inclusion. In my original question, I mentioned that I tried this and found I couldn't use compile-on-save. However, that was because I was trying to use the "watch" option, when I really should have been using the "compileOnSave" option.

Here's my complete set of working steps to transform my original, broken project into one that works properly and will continue to work properly on an unmodified install of Visual Studio 2017.

Add a tsconfig.json file to your project at the root.

Configure your file with at least:

{ "compilerOptions": { "types": [] } } 

but perhaps with other options as you like. My file looks like this:

{   "compileOnSave": true,   "compilerOptions": {     "types": [],     "sourceMap": true,     "target": "es5",     "noEmitOnError": true   } } 

You can learn about other compiler options here: https://www.typescriptlang.org/docs/handbook/compiler-options.html

It's the "types":[] part that prevents the automatic inclusion of definitions.

That means it's up to you to bring in definitions for whatever libraries you use. Fortunately, it's super easy via NuGet. For example, for jQuery, just search for jquery.TypeScript.DefinitelyTyped and install the appropriate version. This will create folders under Scripts/typings.

If you were previously having errors, you might need to clear out some cruft. Clean your project, delete the obj directory at the top of your project's directory structure, and it should now build correctly. I had a couple stray errors that went away when I typed something in the file and then saved again. A restart of Visual Studio might be in order too.

Good luck!


UPDATE: I discovered that when I publish to Azure, I got errors again. However, when I added the directives suggested by Perfa below to my tsconfig.json file, deleted my bin and obj directories and restarted Visual Studio, those errors no longer appeared either. I've now built and rebuilt and published to Azure several times and they seem well and truly gone.

For clarity, my complete tsconfig.json file now looks like this:

{   "compileOnSave": true,   "compilerOptions": {     "types": [],     "sourceMap": true,     "target": "es5",     "noEmitOnError": true   },   "exclude": [     "node_modules",     "obj",     "bin"   ] } 
like image 114
Brian Rak Avatar answered Sep 22 '22 16:09

Brian Rak


after installing VS 2017 I got this error. To get rid of it I updated my tsconfig.json exclude section with obj, and bin.

"exclude": [     "node_modules",     "obj",     "bin"   ] 
like image 21
Perfa Avatar answered Sep 22 '22 16:09

Perfa