Table of Contents
I recently had my hard time trying to setup an ASP.NET Core 1.0 & Angular2 RC1 Web Project with Visual Studio 2015 and make the embedded TypeScript compiler/transpiler accept it. These were the errors I was facing:
1 2 3 4 5 |
TS2304: Cannot find name 'Map'. TS2304: Cannot find name 'Set'. TS2304: Cannot find name 'Promise'. TS2304: Cannot find name 'MapConstructor'. TS2304: Cannot find name 'SetConstructor'. |
As far as I knew, the issue was indeed related to the recent upgrade I made switching Angular2 beta to Angular2 RC1. I managed to fix that, but it took a fair amount of time due to the lack of documentation almost anywhere. Since I feel like it can happen to other developers, I will share the workarounds I found hoping to help someone to waste less time than I had to.
The Problem
Long story short, the issue seems to happen when you're dealing with TypeScript files using ES6 methods without making the transpiler aware about them. That's certainly the case of Angular2 RC1 to RC4, which happened to be my specific scenario, but the exact same thing will most likely happen with a number of other modern TS-based libraries.
You might now ask: "what does making the transpiler aware exactly means?" Well, that's a good question. It basically means that we need to:
- Ensure that we're using a Typescript transpiler that can handle ES6, either by upgrading it or by using a compatibility shim. If you don't know what a shim is, I strongly suggest you to read the following Microsoft article. In short words, a shim is a small library which transparently intercepts an API, changes the parameters passed, handles the operation itself, or redirects the operation elsewhere.
- Ensure that the aforementioned, ES6-aware Typescript transpiler can fetch the proper typings. Typings, or Type Definitions, are what the TypeScript transpiler needs to properly resolve Node module names by following the Node.js module resolution algorithm. If you want to read more about them, I suggest you to read the relevant chapter from the official TypeScript documentation. Back to the topic, it's worth noticing that the TypeScript compiler does what it can to automatically find the typings by looking for a
package.json file and/or a
index.d.ts file in each package root folder: most of the times, that's enough to find what's needed to compile the scripts: however, it can happen that one or more alpha, beta and/or RC library packages we've been using could be missing some typings, or even the whole typings (or typings reference) file. When we're hitting these scenarios, we need to manually guide the transpiler to the typings.
The Fix
The following workarounds have been tested against Angular2 RC1 through RC4, thus they should also work for any other similar packages affected with the same issue.
Method 1: Transpile into ES6
The easiest workaround is to simply switch the transpiler's target from ES5 to ES6. To do that, change your
tsconfig.jsonfile to match the following values:
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "compilerOptions": { "target": "es6", "module": "system", "moduleResolution": "node", ... }, "exclude": [ "node_modules", ... ] } |
However, doing that could bring in some issues: you could be unable to use some of your tools/packages/libraries who don't support ES6 yet, such as UglifyJS. If that's not the case you're good to go, otherwise keep reading.
Method 2: Install Typings and core-js Type Definition Files
Before going for this method, ensure that your
tsconfig.jsonfile matches the following values:
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "compilerOptions": { "target": "es5", "module": "system", "moduleResolution": "node", ... }, "exclude": [ "node_modules", ... ] } |
Open the
package.jsonfile (the one enumerating the NPM packages) and check if the
typingspackage is already present within the
dependenciesor
devDependenciesnode, together with the script required to run it during the post-install phase within the
scriptblock. If they're not here, add them so that your file should look like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "version": "1.0.0", "name": "YourProject", "private": true, "dependencies": { ... "typings": "^1.3.2", ... }, "devDependencies": { ... }, "scripts": { "postinstall": "typings install" } } |
Right after that, add a new
typings.jsonfile to your project's root and fill it with the following:
1 2 3 4 5 6 7 |
{ "globalDependencies": { "core-js": "registry:dt/core-js#0.0.0+20160602141332", "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", "node": "registry:dt/node#6.0.0+20160621231320" } } |
... And then you're done: now your ES6 TypeScript packages should compile without issues.
NOTE: To be honest, the core-js line in the
typings.jsonfile is the only required one, yet we've also took the chance to add the jasmine and node typings: you could need them in the near future, should you want to use the Jasmine test framework and/or use code that references objects in the nodejs environment. Keep them there for now, they won't hurt your project.
Conclusions
While Method 1 is definitely trivial, what we did in Method 2 is also quite straightforward. We installed the typings package through NPM, configured it to download some useful type definition files (core-js being the required one) using its very own
typings.jsonconfig file, and finally we told our project to run it after each NPM task.
We might now be wondering about what core-js actually is, so it could be wise to spend a couple words about it. Remember when we talked about shims a while ago? Well, core-js is our shim of choice, being it a general-purpose polyfill for ECMAScript 5 and ECMAScript 6 including the following: promises, symbols, collections, iterators, typed arrays, ECMAScript 7+ proposals, setImmediate, & much more. If you ever heard of es6-shim, you can think about something that does that exact same job, but better.
That's it for now: happy transpiling!