Книга: Angular 2 Cookbook
Назад: Composing package.json for a minimum viable Angular 2 application
Дальше: Performing in-browser transpilation with SystemJS

Configuring TypeScript for a minimum viable Angular 2 application

In order to use TypeScript alongside Angular 2, there are two major considerations: module interoperability and compilation. You'll need to handle both in order to take your application's .ts files, mix them with external library files, and output the files that would be compatible with your target device.

TypeScript comes ready as an npm package, but you will need to tell it how to interact with the files and modules you've written, and with files from other packages that you want to use in your modules.

Note

The code, links, and a live example of this are available at .

Getting ready

You should first complete the instructions mentioned in the preceding recipe. This will give you the framework necessary to define your TypeScript configuration.

How to do it...

To configure TypeScript, you'll need to add declaration files to incompatible modules and generate a configuration file that will specify how the compiler should work.

Declaration files

TypeScript declaration files exist to specify the shape of a library. These files can be identified by a .d.ts suffix. The majority of npm packages and other JavaScript libraries already include these files in a standardized location, so that TypeScript can locate them and learn about how the library should be interpreted. Libraries that don't include these need to be given the files, and fortunately the open source community already provides a lot of them.

Two libraries that this project uses don't have declaration files: node and core-js. As of TypeScript 2.0, you are able to natively install the declaration files for these libraries directly through npm. The -S flag is a shorthand for saving them to package.json:

 npm install -S @types/node @types/core-js 

A sensible place for this is inside the postinstall script.

tsconfig.json

The TypeScript compiler will look for the tsconfig.json file to determine how it should compile the TypeScript files in this directory. This configuration file isn't required, as TypeScript will fall back to the compiler defaults; however, you want to manage exactly how the *.js and *.map.js files are generated. Modify the tsconfig.json file to appear as follows:

[tsconfig.json]      {     "compilerOptions": {       "target": "es5",       "module": "commonjs",       "moduleResolution": "node",       "emitDecoratorMetadata": true,       "experimentalDecorators": true,       "noImplicitAny": false     }   }   

The compilerOptions property, as you might expect, specifies the settings the compiler should use when the compiling process finds TypeScript files. In the absence of a files property, TypeScript will traverse the entire project directory structure searching for *.ts and *.tsx files.

All the compilerOptions properties can be specified equivalently as command-line flags, but doing so in tsconfig.json is a more organized way of going about your project.

  • target specifies the ECMAScript version that the compiler should output. For broad browser compatibility, ES5 is a sensible default here. Recall that ECMAScript is the specification upon which JavaScript is built. The newest finished specification is ES6 (also called ES2015), but many browsers do not fully support this specification yet. The TypeScript compiler will compile ES6 constructs, such as class and Promise, to non-native implementations.
  • module specifies how the output files will handle the modules in the output files. Since you cannot assume that browsers are able to handle ES6 modules, the TypeScript compiler will have to convert them into a module system that browsers are able to handle. CommonJS is a sensible choice here. The CommonJS module style involves defining all the exports in a single module as properties of a single "exports" object. The TypeScript compiler also supports AMD modules (require.js style), UMD modules, SystemJS modules, and of course, leaving the modules as their existing ES6 module style. It's out of the scope of this recipe to dive deep into modules.
  • moduleResolution defines how module paths will be resolved. It's not critical that you understand the exact details of the resolution strategy, but the node setting will give you the proper output format.
  • emitDecoratorMetadata and experimentalDecorators enable TypeScript to handle Angular 2's use of decorators. Recall the addition of the reflect-metadata library to support experimental decorators. These flags are the point where it is able to tie into the TypeScript compiler.
  • noImplicitAny controls whether or not TypeScript files must be typed. When set to true, this will throw an error if there is any missed typing in your project. There is an ongoing discussion regarding whether or not this flag should be set, as forcing objects to be typed is obviously useful to prevent errors that may arise from ambiguity in codebases. If you'd like to see an example of the compiler throwing an error, set noImplicitAny to true and add constructor (foo) {} inside AppComponent. You should see the compiler complain about foo being untyped.

How it works...

Running the following command will start up the TypeScript compiler from the command line at the root level of your project directory:

 npm run tsc 

The compiler will look for tsconfig.json if it is there and fall back to its defaults otherwise. The settings within direct the compiler how to handle and validate the files, which is where everything you just set up comes into play.

The TypeScript compiler doesn't run the code or meaningfully understand what it does, but it can detect when different pieces of the application are trying to interact in a way that doesn't make sense. The .d.ts declaration file for a module gives TypeScript a way to inspect the interface that the module will make available for consumption when it is imported.

For example, suppose that auth is an external module that contains a User class. This would then be imported via the following:

import {User} from './auth';   

By adding the declaration file to the imported module, TypeScript is able to check that the User class exists; it also behaves in the way you are attempting to in the local module. If it sees a mismatch, it will throw an error at compilation.

Compilation

Depending on your framework experience, this may be something you have or have not had experience with previously. Angular 2 (among many frameworks) operates under the notion that JavaScript, as it currently exists, is insufficient for writing good code. The definition of "good" here is subjective, but all frameworks that require compilation want to extend or modify JavaScript in some form or another.

However, all platforms that these applications need to run on—for your purposes, web browsers—only have a JavaScript execution environment that executes from uncompiled code. It isn't feasible for you to extend how the browser handles payloads or delivers a compiled binary, so the files that you send to the client must play by its rules.

TypeScript, by definition and design, is a strict superset of ES6, but these extensions can't be used natively in a browser. Even today, the majority of browsers still do not fully support ES6. Therefore, a sensible objective is to convert TypeScript into ES5.1, which is the ECMAScript standard that is supported on all modern browsers. How you arrive at this output can occur in one of two ways:

  • Send the TypeScript to the client as is. There are in-browser compilation libraries that can perform a compilation on the client and execute the resulting ES5.1-compliant code as normal JavaScript. This method makes development easier since your backend doesn't need to do much other than serve the files; however, it defers computing to the client, which degrades performance and is therefore considered a bad practice for production applications.
  • Compile the TypeScript into JavaScript before sending it to the client. The overwhelming majority of production applications will elect to handle their business this way. Especially since static files are often served from a CDN or static directory, it makes good sense to compile your descriptive TypeScript codebase into JavaScript files as part of a release and then serve those files to the client.

Tip

When you look at the compiled JavaScript that results from compiling TypeScript, it can appear awfully brutal and unreadable. Don't worry! The browser does not care how mangled the JavaScript files are as long as they can be executed.

With the compiler options you've specified in this recipe, the TypeScript compiler will output a .js file of the same name right next to its source, the .ts file.

There's more...

By no means is the TypeScript compiler limited to a one-off .ts file generation. If offers you a broad range of tooling functions for specifying exactly how your output files should appear.

Source map generation

The TypeScript compiler is also capable of generating source maps to go along with output files. If you're not familiar with them, the utility of source maps stems from the nature of compilation and minification: files being debugged in the browsers are not the files that you have written. What's more, when using a compiled TypeScript, the compiled files won't even be in the same language.

Source maps are indexes that pair with compiled files to describe how they originally appeared before they were compiled. More specifically, the .js.map files contain an encoding scheme that associates the compiled and/or minified tokens with their original name and structure in the uncompiled.ts file. Browsers that understand how to use source maps can reconstruct how the original file appeared and allow you to set breakpoints, step through, and inspect lexical constructs inside it as if it were the original.

Source maps can be specified with a special token added to the compiled file://# sourceMappingURL=/dist/example.js.map

If you want to generate source map files for the output, you can specify this in the configuration file as well by adding "sourceMap": true. By default, the .js.map files will be created in the same place as the output .js files; alternatively, you can direct the compiler to create the source maps inside the .js file itself.

Tip

Even though extraneous map files won't affect the resultant application behavior, adding them inline may be undesirable if you don't want to bloat your .js payload size unnecessarily. This is because clients that don't want or need the map files can't decline to request them.

Single file compilation

Since TypeScript checks all the linked modules against their imports and exports, there's no reason you need to have all the compiled files exist as 1:1 mappings to their input files. TypeScript is perfectly happy to combine the compiled files into a single file if the output module format supports it. Specify the single file where you wish all the modules to be compiled with "outFile": "/dist/bundle.js".

Note

Certain output module formats, such as CommonJS, won't work as concatenated modules in a single file, so using them in conjunction with outFile will not work. As of the TypeScript 1.8 release, AMD and system output formats are supported.

If you plan on using SystemJS, this compiler option can potentially help you, as System works with virtually any module format. If, however, you're using a CommonJS-based bundler, such as Webpack, it's best to delegate the file combination to the bundler.

See also

  • Composing package.json for a minimum viable Angular 2 application describes how all the pieces work for the core node project file
  • Performing in-browser transpilation with SystemJS demonstrates how SystemJS can be used to connect uncompiled static files together
  • Composing application files for a minimum viable Angular 2 application walks you through how to create an extremely simple Angular 2 app from scratch
  • Migrating the minimum viable Angular 2 application to Webpack bundling describes how to integrate Webpack into your Angular application build process
Назад: Composing package.json for a minimum viable Angular 2 application
Дальше: Performing in-browser transpilation with SystemJS

thank you
Flame
cant read the code since it is all on a single line. Also this comments section is russian
Rakuneque
DATA COLLECTION AND ANALYSIS Two reviewers extracted data and assessed methodological quality independently lasix torsemide conversion Many others were in that space already