mrK mrK - 8 days ago 7
TypeScript Question

Visual Studio Typescript - duplicate global identifier

I'm attempting to set up a visual studio solution leveraging angular 2. To start, I'm building the simple program covered in this tutorial:
https://angular.io/docs/ts/latest/guide/setup.html

These are the 3 TS files that are created:

inventory.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { InventoryComponent } from './inventory.component'

@NgModule({
imports: [BrowserModule],
declarations: [InventoryComponent],
bootstrap: [InventoryComponent]
})


export class InventoryModule {
}


inventory.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'inventory',
template: `<h1>Hello {{name}}</h1>`
})
export class InventoryComponent { name = 'Angular'; }


inventory.boot.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { InventoryModule } from './inventory.module';

platformBrowserDynamic().bootstrapModule(InventoryModule);


I'm getting this error when I run the application in chrome:
inventory.module.js:12 Uncaught SyntaxError: Identifier 'core_1' has already been declared

This is happening because the import statements in typescript all transpile to a line that looks like this:
const core_1 = require('@angular/core');

As a result, multiple files have these globally declare constants, all transpiled with the name core_1.

Obviously there's some sort of workaround out there for this, but I've had a lot of trouble finding anything. Can anybody suggest something? Thanks in advance!

EDIT
Per Request, posting my typescript config:
tsconfig.json

{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
"sourceMap": true,
"experimentalDecorators": true
}
}


In addition, there are some properties in the .csproj file that are applicable:

<TypeScriptModuleKind>CommonJs</TypeScriptModuleKind>
<TypeScriptCompileOnSaveEnabled>True</TypeScriptCompileOnSaveEnabled>
<TypeScriptEmitDecoratorMetadata>True</TypeScriptEmitDecoratorMetadata>
<TypeScriptExperimentalDecorators>True</TypeScriptExperimentalDecorators>
<TypeScriptGeneratesDeclarations>False</TypeScriptGeneratesDeclarations>
<TypeScriptJSXEmit>None</TypeScriptJSXEmit>
<TypeScriptModuleResolution>Node</TypeScriptModuleResolution>
<TypeScriptNoEmitOnError>True</TypeScriptNoEmitOnError>
<TypeScriptNoImplicitAny>True</TypeScriptNoImplicitAny>
<TypeScriptRemoveComments>True</TypeScriptRemoveComments>
<TypeScriptSourceMap>True</TypeScriptSourceMap>
<TypeScriptTarget>ES6</TypeScriptTarget>


Just to explain some of these choices


  • ES6 is the target because I get compiler errors in visual studio when referencing angular2 (since it relies on ES6 objects such as Promise)

  • Module Resolution is Node because I need tsc to walk the node tree to obtain the references to angular 2

  • The Module kind was originally AMD, but I needed to change it to CommonJs because I got the error "define is not defined" at runtime in the browser.


Answer

The reason you're getting duplicate identifier errors is because each of your CommonJS modules is viewed as having the same scope by the browser. CommonJS environments like Node implicitly assume that each file has its own scope.

Then, each of the declarations that TypeScript emits are const declarations, but JavaScript errors when it encounters two let or const declarations of the same name.

The Module kind was originally AMD, but I needed to change it to CommonJs because I got the error "define is not defined" at runtime in the browser.

This is because you didn't have an AMD loader (like Require.js) included and configured on your page.

You'll need to use some sort of module loader or bundler to use modules in the browser.

  1. Use System.js if you're using systemjs.
  2. Use Require.js if you're targeting AMD.
  3. Use Webpack or Browserify work if you're using CommonJS.

For System.js and AMD, you'll need a <script> tag and an initial configuration on your page for it to work correctly.

ES6 is the target because I get compiler errors in visual studio when referencing angular2 (since it relies on ES6 objects such as Promise)

You probably don't want to target ES6, since older browsers can't use ES6 constructs, so ES5 is a better choice. However, if you're including a Promise polyfill (like core-js or es6-shim), you can set your lib (or your MSBuild <TypeScriptLib>) to the following:

dom,es2015,es5