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:
...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.
var foo = $(document);
{ "compilerOptions": { "types": [] } }
<Project>\obj\Debug\...
(path was longer but I forgot to record it)obj
directory manually.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:
UPDATE 3: I finally got it working. See the answer below for a non-hacky solution.
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"
]
}