Angular 2 with TypeScript Configuration

Set up and configure an application with Angular 2 and TypeScript.

Last updated Jan 2017, Angular version 2.4.x

NPM and CDN

We're going to look at a couple ways to configure Angular with TypeScript.

First we'll load resources from a content delivery network (CDN), then switch to using node package manager to create the required dependencies for our application.

Then we'll see how to compile the TypeScript into JavaScript during development, and finally how to compile the TypeScript in the browser at runtime.

Using a Content Delivery Network

We add the JavaScript files highlighted in the source code to index.html.

shim.min.js is a polyfill for older browsers which monkey patches the global context (window) with essential ES6 features. zone.js and reflect-metadata.js are polyfills for Angular itself.

SystemJS is our module loader which is configured using systemjs.config.js. We'll take a look at this file next.

The main thing to notice here is that the scripts are being loaded from the unpkg content delivery network.

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Angular Block Counter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Polyfill for older browsers --> <script src="https://unpkg.com/core-js/client/shim.min.js"></script> <script src="https://unpkg.com/zone.js@0.7.2?main=browser"></script> <script src="https://unpkg.com/reflect-metadata@0.1.8"></script> <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('app').catch(function(err){ console.error(err); }); </script>
</head> <body> <block-counter>Loading...</block-counter> </body> </html>

SystemJS

The systemjs.config.js file is used to configure SystemJS for our Angular application.

We create a map to tell SystemJS where to look when we import a module. For example, any modules imported from @angular/forms will be loaded from npm:@angular/forms/bundles/forms.umd.js.

Importantly, the npm: prefix at the start of each package name has been set to https://unpkg.com/ in the paths section, which instructs SystemJS to load these modules from the CDN.

systemjs.config.js
/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'https://unpkg.com/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'app',

            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

            // other libraries
            'rxjs': 'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
            'typescript': 'npm:typescript/lib/typescript.js',
            'ts': 'npm:plugin-typescript/lib/plugin.js'
        },

        transpiler: 'ts',
        typescriptOptions: {
            tsconfig: true
        },
        meta: {
            'typescript': {
                "exports": "ts"
            }
        },

        // packages tells the System loader how to load when no filename and/or no extension
        packages: {
            app: {
                main: './main.ts',
                defaultExtension: 'ts'
            },
            rxjs: {
                defaultExtension: 'js'
            }
        }
    });
})(this);

Reference

For more information about the settings in this file see SystemJS Configuration API, or for more information about SystemJS in general see the SystemJS github repo.

Node Packages

As an alternative to fetching our resources from a CDN, we can include them as part of the application and serve them up from our web server. But to do this we must download and install the relevant modules using the node package manager (NPM).

Node Package Manager

In the project root, we add this package.json file to specify the dependencies for our application.

package.json
{
  "name": "angular-quickstart",
  "version": "1.0.0",
  "description": "QuickStart package.json from the documentation, supplemented with testing support",
  "scripts": {
    "start": "tsc && concurrently \"tsc -w\" \"lite-server\" ",
    "e2e": "tsc && concurrently \"http-server -s\" \"protractor protractor.config.js\" --kill-others --success first",
    "lint": "tslint ./app/**/*.ts -t verbose",
    "lite": "lite-server",
    "pree2e": "webdriver-manager update",
    "test": "tsc && concurrently \"tsc -w\" \"karma start karma.conf.js\"",
    "test-once": "tsc && karma start karma.conf.js --single-run",
    "tsc": "tsc",
    "tsc:w": "tsc -w"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@angular/common": "~2.4.0",
    "@angular/compiler": "~2.4.0",
    "@angular/core": "~2.4.0",
    "@angular/forms": "~2.4.0",
    "@angular/http": "~2.4.0",
    "@angular/platform-browser": "~2.4.0",
    "@angular/platform-browser-dynamic": "~2.4.0",
    "@angular/router": "~3.4.0",

    "angular-in-memory-web-api": "~0.2.2",
    "systemjs": "0.19.40",
    "core-js": "^2.4.1",
    "reflect-metadata": "^0.1.8",
    "rxjs": "5.0.1",
    "zone.js": "^0.7.4"
  },
  "devDependencies": {
    "concurrently": "^3.1.0",
    "lite-server": "^2.2.2",
    "typescript": "~2.0.10",

    "canonical-path": "0.0.2",
    "http-server": "^0.9.0",
    "tslint": "^3.15.1",
    "lodash": "^4.16.4",
    "jasmine-core": "~2.4.1",
    "karma": "^1.3.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-cli": "^1.0.1",
    "karma-jasmine": "^1.0.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~4.0.14",
    "rimraf": "^2.5.4",

    "@types/node": "^6.0.46",
    "@types/jasmine": "^2.5.36"
  },
  "repository": {}
}

We install the node packages by running this command in the project root:

npm install

This will install all the required dependencies in the local node_modules folder (including TypeScript).

Reference

If you are not familiar with Node.js and npm see the npm docs.

Using Node Packages

To use the node packages in our application, we change index.html and the systemjs.config.js to use node_modules rather than the CDN.

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Angular Block Counter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Polyfill for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>

    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
        System.import('app').catch(function(err){ console.error(err); });
    </script>
</head>

<body>
    <block-counter>Loading...</block-counter>
</body>

</html>
systemjs.config.js
/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'node_modules/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'app',

            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

            // other libraries
            'rxjs': 'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
        },
        // packages tells the System loader how to load when no filename and/or no extension
        packages: {
            app: {
                main: './main.js',
                defaultExtension: 'js'
            },
            rxjs: {
                defaultExtension: 'js'
            }
        }
    });
})(this);

TypeScript

Now let's switch our attention to TypeScript. We can compile the TypeScript source files into JavaScript either during development or in the browser at runtime.

In either case, this tsconfig.json file in the root directory is used to configure the TypeScript compiler.

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [ "es2015", "dom" ],
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}

Reference

For general information about the tsconfig.json file see the official TypeScript Wiki. For details about the options that can be specified in this file see the TypeScript compiler options.

Compiling TypeScript During Development

If you don't already have TypeScript, you can install it globally with this command:

npm install -g typescript

To compile the TypeScript locally during development, we can either use a TypeScript-aware IDE such as WebStorm, Visual Studio Code or Sublime Text to compile the TypeScript automatically, or use the following command to run the TypeScript compiler:

tsc

Or we can use this command to run the TypeScript compiler in watch mode:

tsc --watch

This option will automatically re-compile the TypeScript files as they are updated.

Loading JavaScript Files with SystemJS

Because we have already transpiled the TypeScript to JavaScript locally, we can load the JavaScript directly into the browser at runtime.

In the packages section of systemjs.config.js, we tell SystemJS to start with the main.js file and to load all the other files using a default extension of .js.

systemjs.config.js
/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'node_modules/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'app',

            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

            // other libraries
            'rxjs': 'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
        },
// packages tells the System loader how to load when no filename and/or no extension packages: { app: { main: './main.js', defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' } } });
})(this);

Compiling TypeScript in the Browser

As an alternative to compiling locally, we can download the .ts files from the server and transpile the TypeScript to JavaScript in the browser. To do this, we need to make a few changes to our systemjs.config.js file.

First we add the typescript and plugin-typescript libraries to the map option.

Then we set transpiler to 'ts' which tells SystemJS to use plugin-typescript as the default transpiler. In typescriptOptions, setting tsconfig to true ensures that configuration options are taken from tsconfig.json when the TypeScript is compiled.

Finally, in the app property of packages, we change main and defaultExtension to use the .ts versions of the source files.

systemjs.config.js
/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'https://unpkg.com/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'app',

            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

            // other libraries
            'rxjs': 'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'typescript': 'npm:typescript/lib/typescript.js', 'ts': 'npm:plugin-typescript/lib/plugin.js'
},
transpiler: 'ts', typescriptOptions: { tsconfig: true }, meta: { 'typescript': { "exports": "ts" } },
// packages tells the System loader how to load when no filename and/or no extension packages: {
app: { main: './main.ts', defaultExtension: 'ts' },
rxjs: { defaultExtension: 'js' } } }); })(this);

Reference

For more information about plugin-typescript see this github repo.

Where Next?

To find out more about Angular and TypeScript, check out these tutorials.

  • Hello World - Implement a super-simple <hello-world> custom element using an Angular and TypeScript.
  • The Angular with TypeScript Tutorial - includes examples of components, template syntax, property binding, event binding, bootstrapping and more.
  • Templates - introduction to inline and external templates.
  • Interpolation - use curly braces and template expressions to output data on the page.
  • Property Binding - bind to DOM properties using square brackets and template expressions.
  • Event Binding - handle DOM events using parentheses and template statements.
  • Two-way Binding - combine property and event binding to create two-way binding with ngModel.
  • Input Binding - bind to <input> fields such as text, textarea, checkbox, radio and select.
  • Built-in Directives - see how to use built-in directives ngIf, ngSwitch, ngFor, ngClass and ngStyle.
  • Component Input Output - use @Input and @Output to pass data in to and out of a component.
  • Angular Router - Use the Angular router to navigate between components when the user clicks a link.
  • Nested Child Routes - An example of how child routes allow navigation between multiple views when a user clicks a link in a sub-menu.