TypeScript 2.x By Example

4.8 (4 reviews total)
By Sachin Ohri
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Getting Started with TypeScript

About this book

The TypeScript language, compiler, and open source development toolset brings JavaScript development up to the enterprise level. It allows you to use ES5, ES6, and ES7 JavaScript language features today, including classes, interfaces, generics, modules, and more. Its simple typing syntax enables building large, robust applications using object-oriented techniques and industry-standard design principles.

This book aims at teaching you how to get up and running with TypeScript development in the most practical way possible. Taking you through two exciting projects built from scratch, you will learn the basics of TypeScript, before progressing to functions, generics, promises, and callbacks. Then, you’ll get to implement object-oriented programming as well as optimize your applications with effective memory management. You’ll also learn to test and secure your applications, before deploying them. Starting with a basic SPA built using Angular, you will progress on to building, maybe, a Chat application or a cool application. You’ll also learn how to use NativeScript to build a cool mobile application. Each of these applications with be explained in detail, allowing you to grasp the concepts fast.

By the end of this book, you will have not only built two amazing projects but you will also have the skills necessary to take your development to the next level.

Publication date:
December 2017
Publisher
Packt
Pages
372
ISBN
9781787280038

 

Chapter 1. Getting Started with TypeScript

 

"JavaScript that scales."

"TypeScript is a typed superset of JavaScript that compiles to plain JavaScript."

"Any browser, any host, any OS, and open source."

These are official statements by the TypeScript team.

"Surprisingly simple, extraordinarily powerful."

This is how I describe TypeScript.

The purpose of this book is to provide readers with an opportunity to see and understand the preceding quotes and appreciate TypeScript for its power and elegance.

In this chapter, we will introduce TypeScript and take a brief look at its features that help us write client- and server-side (Node.js) applications that are scalable, maintainable, reusable, and future-proof.

The fundamental principle of TypeScript is that it's a superset of JavaScript and all valid JavaScript is a valid TypeScript. This allows developers to start using TypeScript with their existing knowledge of JavaScript and be productive.

We will be covering the following topics in this chapter:

  • We will start by looking at what the common issues/pitfalls of JavaScript are, the so-called not-so-good parts. 
  • Then we will move on to take a look at how TypeScript tries to solve those.
  • We will then dive deeper and explore the features of TypeScript that stand out from its competitors and are the most appealing.
  • We will also look at TypeScript architecture and its features.
  • TypeScript provides support for the wide array of editors; we will look at configuring Visual Studio and Visual Studio Code for TypeScript development.
  • We will get familiar with the TypeScript compiler and how TypeScript allows the configuration of compiler options. TypeScript is amazingly flexible for equipping developers with the power to configure the settings when compiling their code.
  • At the end of this chapter, we will look at some of TypeScript's widely used syntax and keywords. Post that, to kick-start our journey, we will create a small application. We will develop a to-do list in TypeScript where a user can create a new to-do item and its description and view the list. This example will not use any other frameworks such as jQuery but will be purely developed in TypeScript. We will demonstrate how plain TypeScript can work and help us develop web applications.

So, let's get going!

 

The current state of JavaScript


If you have developed any web applications and written more than a few lines of code in JavaScript, you will have encountered one of the many quirks of JavaScript. Web application development has gone through some major changes in the last decade or so. We have been writing more and more complex applications that need to have a highly interactive user interface. There have been libraries which have helped us along the way, such as jQuery, Knockout, and so on, but they can only go so far to manage an ever-expanding code base.

Applications written in JavaScript tend to become cluttered and difficult to maintain after a few hundred lines of code if we do not follow best practices and patterns. To solve this problem, many JavaScript frameworks have come along, such as Durandal, Backbone, React, and Angular, which have helped manage these complexities. They did succeed to some extent, but we were still writing in JavaScript and were still susceptible to its nature.

JavaScript is a very flexible language with features such as dynamic typing, hoisting, and closures. Flexibility comes with a price and if you are building medium- to large-scale applications, this price of writing and managing JavaScript code is very steep. If we don't follow recommended design patterns such as the revealing module pattern or the prototype pattern, we quickly end up with code that is difficult to manage.

 

The not-so-good parts of JavaScript


JavaScript, for all its flexibility and features which make it suitable for web-based applications, has some quirks which, if not understood and implemented correctly, cause applications to have unintended behaviors. If you have done development in JavaScript, you will have read or heard about the good parts of JavaScript, a term made famous by Douglas Crockford, but let's look at the not-so-good parts as well.

Features

The following are the features of JavaScript which should be understood before you can write an effective large-scale application:

  • Type inference
  • Arrays
  • Equality comparison
  • Null and undefined

Type inference

One of the main features of JavaScript is that it's a dynamically typed language. This means a type of a variable is determined at runtime and the compiler does not generate any errors if there is a type mismatch until it fails. We can have the same variable hold a string, a number, an array, or an object and JavaScript will not complain, but it can cause errors at runtime if not handled. JavaScript uses type inference to identify the type of data stored in a variable, based on which it operates on the variable. The following is an example where type inference fails between a number and a string.

In the following code, when num is assigned a value of 1, JavaScript infers it as a number and performs addition when we try to add a value to num. Later, when we assign a string to num, JavaScript infers it as a string and performs concatenation when we try to add a value:

var num = 1;
num += 1;
console.log(typeof(num)); // returns: number
console.log(num);  // returns: 2
num = 'str';
Console.log(typeof(num));  // returns: string
num += 1; // retun: str1

Arrays

Arrays are a very common example of where JavaScript dynamic typing fails. We define an array variable, score, which has the list of scores in it. To fetch the selected elements from an array, we use the slice function. Till the time score is an array, this works, but imagine if someone wanted to assign a single element in an array and instead they assigned a number. Now the same slice function will fail:

var score = [1,2,3,4,5,6];
console.log(score.slice(2, 4)); // returns: [3,4]
score = 10;
console.log(score.slice(2, 4)); // Uncaught TypeError: score.slice is not a function

Equality comparison

If you have a number in quotes, JavaScript will determine it as a string but, if you do a comparison in an if statement to a literal number, then JavaScript will automatically try to convert the string into a number and perform the comparison:

var result = '1';
console.log(result == 1); // returns true
console.log(result === 1); // returns false

Now, this can be something which you may or may not have expected to happen, because sometimes we may not want JavaScript to do these type of comparisons. For small applications, you can make sure that you are passing proper types, but that's not so easy in the case of large-scale applications. One solution would be to use === rather than ==, which makes JavaScript not coerce the type of a variable. These solutions are not intuitive and we have seen many developers making this mistake.

Null or undefined

Like dynamic type, JavaScript allows variables to be assigned null or undefined. Unless proper validations are done every time a variable is accessed, we get to see errors such as undefined is not a function or cannot read property x of undefined. This happens because there are no specific checks in JavaScript by the language to make sure we are not accessing or assigning any variable or function as undefined or null. TypeScript, with its type declaration, reduces the probability of having such issues and, in addition to that, TypeScript has a compiler flag, strictNullChecks, which allows the compiler to flag any instance where the application is assigning any null or undefined type. The TypeScript compiler also does control flow analysis to keep track of whether a variable can be null or undefined.

The control flow analysis means that TypeScript is able to scan through the code and identify whether a specific variable or property can be null or undefined.

<h2>Soft skill

Another challenge can be for the developer with the non-JavaScript background. A lot of developers move from server-side languages such as Java or C# and are accustomed to writing an object-oriented style of code. JavaScript, with its keywords of prototype, does provide a mechanism to achieve most of the object-oriented concepts but these concepts are not easy to understand and use.

TypeScript solves these problems by adding types to the variables, to parameters, and to the return value of functions. Having types defined helps TypeScript to identify and flag such scenarios. TypeScript maintains the flexibility of JavaScript with respect to types by not making it mandatory to define them. TypeScript, similar to JavaScript, infers the type based on the initial value assigned to the variable. If, at a later point in time, the same variable is assigned a conflicting type, TypeScript flags it at design time as well as at compile time.

Note

TypeScript has a special type, any, to handle situations where you are not sure what type value a variable can hold. This comes in especially handy when we want to start using TypeScript in our existing JavaScript project and don't want to migrate the existing code base. If we copy our existing JavaScript code to a TypeScript file (valid JavaScript is a valid TypeScript), TypeScript will try to infer data types for all the variables and parameters and where it's not able to infer, it will assign any as a data type.

 

TypeScript to the rescue


TypeScript is cross-platform language and works on Windows, Linux, and macOS. You can create TypeScript applications on any platform and an IDE of your choice. Modern web application frameworks also support TypeScript, with Angular one of the prominent ones. In fact, Angular 2 has been written in TypeScript by Google.

While developing any large-scale web applications, there is a lot of JavaScript that is involved for things such as validations, navigation, the workflow of the application, UI rendering, API calls, and so on. In my experience, any time JavaScript reaches a few thousand lines of code, it becomes overly complex, which causes unintended behavior and runtime errors. TypeScript provides features which help manage these complexities, such as static typing, encapsulation using modules and classes, custom types, interfaces, and much more.

Benefits of TypeScript

There are many benefits of TypeScript over JavaScript and we will cover a few of them here:

  • TypeScript is a superset of JavaScript. This means any JavaScript code you have is already a valid TypeScript code. You can take your existing JavaScript code, copy it into a TypeScript file, and it will be compiled successfully. This helps developers who have some familiarity with JavaScript to transition to TypeScript.

    The following figure shows where TypeScript resides in the JavaScript ecosystem:

As the preceding figure shows, TypeScript contains all the existing features of ES5 and ES6, and the proposed features of ES7, along with some features which are specific to TypeScript, such as interfaces.

  • The JavaScript language has a handful of types, for example, String, Number, and Boolean, but TypeScript adds in few more primitive types to the list, such as Tuple, Enum, and Never. TypeScript also allows you to create your own custom types in an object-oriented fashion. These types help make your code safer, more manageable, and easier to refactor with fewer bugs, and increases developer productivity. The TypeScript compiler uses all these types to check the code for errors and helps to resolve the issues long before the code is deployed in the production environment. Having types helps create a faster development cycle.
  • TypeScript, with all its types, compiles into vanilla JavaScript so that it can run on any web browser, on any platform, or even on the server side using Node.js. The syntax of TypeScript is not specific to Microsoft technologies but follows the JavaScript ECMA standards. TypeScript follows ES6 (ECMAScript 2015) syntax where possible and for features that are currently not available in ES6, uses the proposed ES7 feature set. TypeScript, under its compiler option, allows you to compile the code to either the ES3, ES5, or ES6 version of JavaScript. The following figure shows the  process of compiling TypeScript to plain old JavaScript:
  • There are a rich set of editors that can be used to program with TypeScript, such as Visual Studio, Visual Studio Code, Sublime, Atom, and so on. If you are using such an editor, it provides you with features such as IntelliSense, design-time error checks, navigation between code paths, renaming, and refactoring options. We will explore editors in the upcoming section.

TypeScript comparison with JavaScript

Let's look at an example of how TypeScript makes life easy with types and error checking. Take a look at the following JavaScript code. It's perfectly legal code, though it is not following the recommended best practices:

function getLargestNumber(arr){
    result=0;
    for( index =0; index < arr.length; index++){      
        if(result < arr[index]){
            result =  arr[index];
        }
    }
    if(result > 0) {
      result = true;
    }
    else result = false;

    return result;
}
score = [1,2,3,4,5,6,];
highestScore= getLargestNumber(score);

The preceding code, when executed, will return true from getLargestNumber, something which you would not have expected.

This code has multiple potential bugs in it:

  • The result, index, score, and highestscore variables are not declared with a var or let keyword so they end up leaking into the global namespace
  • We are using result to store the largest number and then assign a Boolean value to it based on what is stored in result

Now, let's copy this code to the TypeScript file. It immediately shows these errors with a red squiggly line. If you hover over any of these variables, you will see the message Cannot find name 'result'. TypeScript does not allow declaration without a var or let keyword (the let keyword was introduced in ES6). The following screenshot shows the code when copied to a TypeScript file:

Let's add the let keyword before all the variable declarations; this will help us get rid of the first error. For the second issue, where we are assigning two different types of values, number and boolean, to the result variable, TypeScript does not allow that. At line 2, TypeScript implicitly inferred number as a type for the result and when we try to assign boolean on lines 8 and 10, TypeScript alerts us to the error. The following screenshot shows the code after we have added the let keyword for all variable declarations:

There is one more error reported by TypeScript in the preceding code, for input parameter to the function. The error states that Parameter 'arr' implicitly has an 'any' type. This is because we have not defined the type of the input variable. In TypeScript, we can configure our compiler options to enable/disable certain types of errors. This allows teams to create their own rules of what should be termed as an error and what should not. In our application, I have enabled a compiler flag, noImplicitAny, as true. This option informs the compiler to flag variables whose data type is any.

In our example, TypeScript is not able to identify the data type of the variable arr, and hence assigns the any type, which is then flagged as an error. So, let's assign the data type to our variable as shown in the following screenshot:

Now, if we try calling getLargestNumber by passing data other than an array of numbers, TypeScript will flag that as well. The following code will fail because we are trying to call getLargestNumber by assigning an array of strings:

let names=['john,','jane','scott'];
let sortedNames= getLargestNumber(names);

We saw in these examples the benefits of having a strongly-typed language. If we try to assign a number to a variable with the type string, TypeScript will flag it as an error, and if you are using one of the editors which have TypeScript integrated into them, you may end up seeing these errors as you type. If not, then these will be caught by the TypeScript compiler. These benefits help us churn out high-quality code with minimal possible bugs and increased productivity.

With pure JavaScript, you will have to do type checking at every possible point. Never assume that your function will receive the right set of parameters; always check the output returned by a function which may be a number or Boolean as in our case above. TypeScript helps solve all these problems.

Note

TypeScript will compile the code and produce JavaScript even if there are any design-/compile-time errors.

 

Alternatives to TypeScript


To overcome the flaws and limitations of base JavaScript, many alternate programming languages mushroomed, including CoffeeScript, TypeScript, Dart, and recently Flow, that compile to JavaScript, in the end. All these languages are trying to solve challenges such as encapsulation, scoping, and type inference, among others. Some of them have been there for a while and some are pretty new. CoffeeScript is very similar to Python and relies on concise syntax and lambda expressions. Both CoffeeScript and Dart try to encapsulate JavaScript by introducing a new language which would then convert to JavaScript. The primary difference between these languages and TypeScript is that TypeScript does not introduce new syntax but builds on top of JavaScript. If you are a JavaScript developer, it's very easy to start with TypeScript but that's not the same case with these languages.

Flow was introduced by Facebook in 2016 as a way to provide type checking to JavaScript. It is very similar to TypeScript in the sense that the primary purpose is to provide a way to solve the problem of static types. Flow also enjoys significant support, primarily in the Facebook domain of applications such as React and React Native. Both Flow and TypeScript are very good choices to help write robust JavaScript code. One primary difference between Flow and TypeScript is that Flow only does type checking and relies on tools such as Babel to do the transpiling, whereas TypeScript has a very exhaustive set of tools to provide type checking and transpiling.

Another option is to write JavaScript in ES6 (ES2015) format; the advantage of this is that you are writing pure JavaScript and there is no need to do any transpiling or learn a new framework. But, currently, not all browsers support all the features of ES6 and you would have to make use of frameworks such as Babel to convert your ES6 to ES5. TypeScript uses most of the existing ES6 features and adds some features such as types to make the code more robust and error-free.

 

TypeScript features


The TypeScript architecture can be divided into five main components:

  • Core TypeScript compiler: This is the base of the TypeScript language; it manages all the low-level tasks which allow TypeScript to expose its rich set of features and compile the code into JavaScript. The core compiler consists of modules such as type resolver, which is responsible for resolving types, checking semantic operations, and providing error or warning conditions where appropriate, and preprocessor, which manages references between files using import or /// <reference path=…/>.
  • Language service: The language service is a layer on top of the core compiler which exposes features that are required by editors, such as IntelliSense, debugging, statement completion, refactoring using symbols, and formatting. The language service is also responsible for incremental build configuration using the watch flag. This configuration allows the TypeScript compiler to keep watching for any changes to your files and if it detects any changes, the compiler automatically initiates the build.
  • Standalone compiler: The standalone compiler is the high-level compiler exposed by TypeScript. In TypeScript, to compile the code, we use this standalone compiler (tsc) which runs through the TypeScript file (*.ts) and spits out a JavaScript (*.js) file.
  • TypeScript features: The TypeScript features which are exposed to use are provided at this layer. This layer is an abstraction of the language service and the core compiler.
  • Editor plugins: TypeScript supports a wide variety of editors through plugins. Editors such as Visual Studio Code, Visual Studio, Sublime, and Atom are the most popular ones. TypeScript plugins help you write code in these editors by providing support for auto build, IntelliSense, design-time error checking, and so on.

The following diagram shows the high-level architecture of TypeScript:

Features

TypeScript has a rich feature set which creates a very compelling reason for its use. These features provide a platform to write large-scale web applications, all the while keeping code manageable, robust, error-free, and modular.  The following list shows the main features provided by TypeScript as listed here:

  • Data types
  • Control flow analysis
  • Encapsulation
  • Inheritance
  • Interface
  • Shapes
  • Decorators

Now, let's take a look at the features in detail.

Data types

Duck typing is the ability of a language to determine types at runtime. JavaScript follows the duck typing paradigm; it has types but they are determined dynamically and developers don't declare them. TypeScript goes one step further and adds types to the language. Having data types has been proven to increase productivity and code quality, and reduce errors at runtime. It's better to catch errors at compile time rather than have programs fail at runtime. TypeScript provides the feature of inferring types, thus allowing developers to only optionally define types. As seen in the following code, projectStatus is assigned the type number:

let projectStatus = 1;
projectStatus = 'Success';// Error: Type 'Success' is not assignable to type 'number'

TypeScript determined the type as number and then alerted us when we were trying to assign a string. TypeScript also provides features such as union types (we can assign multiple types to a variable) and intersection types. We will be discussing these in detail in the next chapter.

Control flow analysis

TypeScript provides type analysis based on the code flow. Types can be narrowed or broadened based on the code flow. This helps to reduce logical errors when we have multiple types of a variable and logic varies with type as shown in the following code:

function projectStatus (x: string | number) {
    if (typeof x === 'string') { // x is string | number
       x = 10;
    }
    return x; // type of `number
}

TypeScript by code flow analysis determined that the type of x returned from the function is a number.

Encapsulation

Encapsulation is one of the key pillars of object-oriented programming, which states that objects of a function should only expose required members to external code and hide the implementation details. With encapsulation, we provide a flexibility to the system to change its implementation without changing the contract. TypeScript provides encapsulation through the concept of classes, modules, and access modifiers. Classes are like containers which contain common features. Classes expose only the required fields using access modifiers such as private/public/protected. Modules are the containers of classes and provide another level of encapsulation for the group of classes achieving specific functionality:

class News{
    public channelNumber : number;
    public newsTitle: string;
    private url: string;
}
let espn = new News();
espn.channelNumber = 1;
espn.newsTitle = 'NFL Today';
espn.url = 'http://go.espn.com'; // url is private and only accessible inside the class

The espn.url will throw an error because the URL property is private to the class.

Inheritance

In object-oriented programming, inheritance allows us to extend the functionality of a class from a parent class. In TypeScript, we use a keyword, extends, in a child class and refer the parent class. By extending the functionality in the child class, we can have access to all the public members of the parent class:

class Editor { 
  constructor(public name: string,public isTypeScriptCompatible : Boolean) {}

  details() {
    console.log('Editor: ' + this.name + ', TypeScript installed: ' + this.isTypeScriptCompatible);
  }
}

class VisualStudio extends Editor{
    public OSType: string
    constructor(name: string,isTypeScriptCompatible : Boolean, OSType: string) {
        super(name,isTypeScriptCompatible);
        this.OSType = OSType;
    }
}

let VS = new VisualStudio('VSCode', true, 'all');
VS.details();

The VisualStudio class extends the Editor class and hence the instance of VisualStudio inherits the details method.

Interface

The primary purpose of an interface is to drive code consistency. An interface is a contract defined and any class that implements the interface needs to implement all the properties of that interface. The interface is a pure TypeScript concept and is not part of ECMAScript; this means that when TypeScript code is converted to JavaScript, interfaces are not converted:

interface Planet{
    name: string;
    weather: string; 
}

class Earth implements Planet {
    name: string;
    weather: string;
}

let planet: Planet= new Earth();

Shapes

TypeScript allows the flexibility to assign objects with different identifiers if they have the same attributes. This means that if two objects have the same set of attributes then they are considered to be of the same type and we can assign one object to another:

interface Planet{
    name: string;
    weather: string; 
}

class Earth implements Planet {
    name: string;
    weather: string;
}

let planet: Planet;

class Pluto{
    name: string;
    weather: string;   
}

planet = new Pluto()

Here, we assigned an instance of Pluto to planet even though Pluto does not implement Planet. This happens because the attributes and their type in the Pluto class are same as interface .

Decorators

Decorators are a TypeScript-specific concept at the moment, although they are in a stage two proposal for JavaScript (https://github.com/tc39/proposal-decorators). The decorator is one of the structural design patterns from the Gang of Four, which implies adding additional responsibility to an object. In TypeScript, they are experimental features and we need to enable them in the compiler configuration (tsconig.json). TypeScript allows the use of decorators on classes, properties, methods, and accessors. Decorators are commonly used in Angular and we will see the examples in the upcoming chapters.

TypeScript syntax and keywords

The TypeScript program is organized into modules, which contain classes, functions, and variables. Each of these features are achieved using specific keywords, such as export for exposing a class or function to an outside module, and import for accessing a class or function from a different module. The following figure shows the high-level structure of typical TypeScript code. The module is the outermost container which will be composed of multiple classes. Each class will contain variables and functions to provide a specific functionality:

 

The following table provides an overview of some of the keywords available in TypeScript:

Keyword

Description

Basic types

TypeScript has many basic types, such as Boolean, Number, String, Array, Any, Never, Null, and Undefined.

Classes

These are containers for properties and functions. Classes compile into JavaScript functions.

Constructor

Similar to the OOP concept, providing a method which is called when an object of a class is created. It can be used to initialize properties in a class.

Interface

Defines a contract which is then implemented by a class. It can have properties and function declaration.

Implements

Keyword used to inform the compiler which interface is implemented by a class.

...

Rest parameter, which allows a function to accept multiple parameters and receive them as an array.

=>

Fat arrow function, which provides alternate syntax for defining functions.

Module

Container for classes.

Import/export

Keywords used to define which members of a module are exported or imported.

Generics

Generics allow you to write functions which may accept different data types. This allows us to write functions which are reusable.

Enum

Enum allows us to define a set of constants which have numeric values associated with it.

Iterators

Any object which implements System.iterator is iterable. This means that object will return a list of values which can be iterated upon.

 

There are many more keywords and features provided by TypeScript and we will go through them and use them in our examples in subsequent chapters. 

 

Installation and setup


 In this section, we will look at the installation process of TypeScript and the editor setup for TypeScript development. Microsoft does well in providing easy-to-perform steps to install TypeScript on all platforms, namely Windows, macOS, and Linux. 

Installation of TypeScript

TypeScript's official website (https://www.typescriptlang.org) is the best resource to install the latest version of TypeScript. On the website, go to the Download section; there, you will find details on how to install TypeScript. Node.js and Visual Studio are the two most common ways to get TypeScript. TypeScript supports a host of other editors and has plugins available for them in the same link. We will be installing TypeScript using Node.js and using Visual Studio Code as our primary editor. You can use any editor of your choice and be able to run the applications seamlessly. If you use full-blown Visual Studio as your primary development IDE, then you can use either of the links, Visual Studio 2017 or Visual Studio 2013, to download the TypeScript SDK. Visual Studio does come with a TypeScript compiler but it's better to install it from this link so as to get the latest version.

To install TypeScript using Node.js, we will use npm (node package manager), which comes with Node.js. Node.js is a popular JavaScript runtime for building and running server-side JavaScript applications. As TypeScript compiles into JavaScript, Node is an ideal fit for developing server-side applications with the TypeScript language. As mentioned on the TypeScript website, just running the following command in the Terminal (on macOS) / Command Prompt (on Windows) window will install the latest version of TypeScript:

npm install -g typescript

To load any package from Node.js, the npm command starts with npm install; the -g flag identifies that we are installing the package globally. The last parameter is the name of the package that we are installing. Once it is installed, you can check the version of TypeScript by running the following command in the Terminal window:

tsc -v

You can use the following command to get the help for all the other options that are available with tsc:

tsc -h

TypeScript editors

One of the outstanding features of TypeScript is its support for editors. All the editors provide support for TypeScript language services, thereby providing features such as IntelliSense, statement completion, and error highlighting. If you are coming from a .NET background, then Visual Studio 2013/2015/2017 is a good option for you. Visual Studio does not require any configuration and it's easy to start using TypeScript. As we discussed earlier, just install the SDK and you are good to go. If you are from a Java background, TypeScript supports Eclipse as well. TypeScript also supports plugins for Sublime, WebStorm, and Atom, and each of these provides all the rich feature sets.

Visual Studio Code (VS Code) is another good option for an IDE. It's a smaller, lighter version of Visual Studio and primarily used for web application development. VS Code is lightweight and cross-platform, capable of running on Windows, Linux, and macOS. It has an ever-increasing set of plugins to help you write better code, such as TSLint, a static analysis tool to help TypeScript code for readability, maintainability, and error checking. VS Code has a compelling case to be the default IDE for all sorts of web application development. In this section, we will briefly look at the Visual Studio and VS Code setup for TypeScript.

Visual Studio

Visual Studio is a full-blown IDE provided by Microsoft for all .NET based development, but now Visual Studio also has excellent support for TypeScript with built-in project templates. A TypeScript compiler is integrated into Visual Studio to allow automatic transpiling of code to JavaScript. Visual Studio also has the TypeScript language service integrated to provide IntelliSense and design-time error checking, among other things.

With Visual Studio, creating a project with a TypeScript file is as simple as adding a new file with a .ts extension. Visual Studio will provide all the features of TypeScript out of the box.

VS Code

VS Code is a lightweight IDE from Microsoft used for web application development. VS Code can be installed on Windows, macOS, and Linux-based systems. VS Code can recognize the different type of code files and comes with a huge set of extensions to help in development. You can install VS Code from https://code.visualstudio.com/download.

VS Code comes with an integrated TypeScript compiler, so we can start creating a TypeScript project directly. The following screenshot shows a TypeScript file opened in VS Code:

To run the project in VS Code, we need a task runner. VS Code includes multiple task runners which can be configured for the project, such as Gulp, Grunt, and TypeScript. We will be using the TypeScript task runner for our build.

VS Code has a Command Palette which allows you to access various different features, such as Build Task, Themes, Debug options, and so on. To open the Command Palette, use Ctrl + Shift + P on a Windows machine or Cmd + Shift + P on a macOS. In the Command Palette, type Build, as shown in the following screenshot, which will show the command to build the project:

When the command is selected, VS Code shows an alert, No built task defined..., as follows:

 

We select Configure Build Task and, from all the available options as shown in the following screenshot, choose TypeScript build:

This creates a new folder in your project, .vscode and a new file, task.json. This JSON file is used to create the task that will be responsible for compiling TypeScript code in VS Code.

TypeScript needs another JSON file (tsconfig.json) to be able to configure compiler options. Every time we run the code, tsc will look for a file with this name and use this file to configure itself. TypeScript is extremely flexible in transpiling the code to JavaScript as per developer requirements, and this is achieved by configuring the compiler options of TypeScript.

 

TypeScript compiler


The TypeScript compiler is called tsc and is responsible for transpiling the TypeScript code to JavaScript. The TypeScript compiler is also cross-platform and supported on Windows, macOS, and Linux.

To run the TypeScript compiler, there are a couple of options. One is to integrate the compiler in your editor of choice, which we explained in the previous section. In the previous section, we also integrated the TypeScript compiler with VS Code, which allowed us to build our code from the editor itself. All the compiler configurations that we would want to use are added to the tsconfig.json file.

Another option is to use tsc directly from the command line / Terminal window. TypeScript's tsc command takes compiler configuration options as parameters and compiles code into JavaScript. For example, create a simple TypeScript file in Notepad and add the following lines of code to it. To create a file as a TypeScript file, we just need to make sure we have the file extension as *.ts:

class Editor {  
  constructor(public name: string,public isTypeScriptCompatible : Boolean) {}
  details() {
    console.log('Editor: ' +  this.name + ', 
                 TypeScript installed: ' + 
                 this.isTypeScriptCompatible);
  }
}

class VisualStudioCode extends Editor{
    public OSType: string
    constructor(name: string,isTypeScriptCompatible : Boolean,
                OSType: string) {
        super(name,isTypeScriptCompatible);
        this.OSType = OSType;
    }
}

let VS = new VisualStudioCode('VSCode', true, 'all');
VS.details();

This is the same code example we used in the TypeScript features section of this chapter. Save this file as app.ts (you can give it any name you want, as long as the extension of the file is *.ts). In the command line / Terminal window, navigate to the path where you have saved this file and run the following command:

tsc app.ts

This command will build the code and the transpile it into JavaScript. The JavaScript file is also saved in the same location where we had TypeScript. If there is any build issue, tsc will show these messages on the command line only.

As you can imagine, running the tsc command manually for medium- to large-scale projects is not a productive approach. Hence, we prefer to use an editor that has TypeScript integrated. 

The following table shows the most commonly used TypeScript compiler configurations. We will be discussing these in detail in upcoming chapters:

Compiler option

Type

Description

allowUnusedLabels

boolean

By default, this flag is false. This option tells the compiler to flag unused labels.

alwaysStrict

boolean

By default, this flag is false. When turned on, this will cause the compiler to compile in strict mode and emit use strict in the source file.

module

string

Specify module code generation: None, CommonJS, AMD, System, UMD, ES6, or ES2015.

moduleResolution

string

Determines how the module is resolved.

noImplicitAny

boolean

This property allows an error to be raised if there is any code which implies data type as any. This flag is recommended to be turned off if you are migrating a JavaScript project to TypeScript in an incremental manner.

noImplicitReturn

boolean

Default value is false; raises an error if not all code paths return a value.

noUnusedLocals

boolean

Reports an error if there are any unused locals in the code.

noUnusedParameter

boolean

Reports an error if there are any unused parameters in the code.

outDir

string

Redirects output structure to the directory.

outFile

string

Concatenates and emits output to a single file. The order of concatenation is determined by the list of files passed to the compiler on the command line along with triple-slash references and imports. See the output file order documentation for more details.

removeComments

boolean

Remove all comments except copyright header comments beginning with /*!.

sourcemap

boolean

Generates corresponding .map file.

Target

string

Specifies ECMAScript target version: ES3(default), ES5, ES6/ES2015, ES2016, ES2017, or ESNext.

Watch

 

Runs the compiler in watch mode. Watches input files and triggers recompilation on changes.

 

 

TypeScript to-do list application


It's time to create our to-do list application. In this application, we will have the following features:

  • Add a new item with its description to the to-do list
  • View all the items in the list

The application is very simple, as our focus is on looking at how TypeScript helps build better web applications. With this application, we intend to show you how to create an application with TypeScript, showcase the basic features of TypeScript, show you how to debug TypeScript code in the browser, and give you an overview of the JavaScript code that's generated by TypeScript.

You can find the source code on GitHub at https://github.com/sachinohri/TypeScriptTodo.git.

The following screenshot shows what the application looks like:

The application has no dependencies on any JavaScript library and is purely written in TypeScript. In this application, we have written all our code in a single file (todo.ts) just to keep it concise, although in real-world applications, we would want to create separate files to reduce code complexity and have separation of concerns.

Starting a new project in VS Code is fairly simple: just select Open Folder and browse to the folder where you would want to create a new project. If you are opening an existing project, then browse to that folder and VS Code will open the project for you. Our Todo application has a very basic code structure with the following folders/files:

  • The .vscode folder which was created by VS Code when we configured our build task. You can refer to the Installation and setup section of this chapter for more details on how this folder is created.
  • The app folder where we have our todo.ts file. When we build our project, the TypeScript compiler generates todo.js and todo.js.map files for our TypeScript file in the same folder.
  • We also have a site.css file to provide some basic styling to our project, in addition to bootstrap.
  • The tsconfig.json file is used by the TypeScript compiler to configure its build task.
  • The index.html file is our user interface and has reference to the todo.js file. This file just has basic features such as an input group to add a new item and a list group to show the existing items.

Our main code lies inside the todo.ts file and we will focus on that.

todo.ts

The todo.ts file contains a couple of classes—todo and todolist—and has an interface ITodo. 

We have a Todo class, which has three properties: name, description, and completed. The Todo class implements an interface ITodo:

interface ITodo{
    name:string;
    description: string;
    completed: boolean;
}

Implementing an interface helps maintain code consistency; in large applications, if any class implements an interface, that would act as a contract between the class which implements the interface and the class/module which creates an object of this class. An interface provides code abstraction and helps us create more manageable code. As we discussed earlier, an interface is just a TypeScript concept and, upon compilation, no JavaScript code is generated.

TypeScript provides a couple of ways to declare and assign values to member variables of a class:

  • We can create three variables and then assign values to them inside the constructor function as follows:
class Todo implements ITodo{
    public name:string;
    public description: string;
    public completed: boolean;
    constructor(name:string, description:string, completed:boolean){
        this.name = name;
        this.description = description;
        this.completed = completed;
    }
}

Here we have three public variables in a class which is initialized inside the constructor.

  • Another way, which is more concise, is seen in the following code snippet. Here, in the constructor itself, we declare the variables and TypeScript makes sure that they get initialized as well when the object of the class is created:
class Todo implements ITodo{
    constructor(public name: string, 
                public description: string, 
                public completed: boolean){}
}

We have another class, TodoList, which contains all the logic for our application. We have a static property of the type Todo Array which will persist all the Todo elements. It has two functions,  createTodoItem and allTodoItems, which are responsible for creating a new todo task and returning all the todo tasks respectively: 

class TodoList{
    public static allTodos: Todo[]= new Array;
    createTodoItem(name:string,description:string):number {
        let newItem = new Todo(name,description, false);
        let totalCount: number = TodoList.allTodos.push(newItem);
        return totalCount;
    }

    allTodoItems():Todo[]{
        return TodoList.allTodos;
    }
}

We will go deeper into classes of TypeScript in later chapters; here, we will just look at the basic syntax and how functions are defined inside the class.

Classes in TypeScript

Declaring a function is straightforward, with the function name, set of parameters, and then, inside curly braces, the implementation. After the set of parameters is declared, we can also annotate the function with the data type of the return value from the function. By default, all properties and functions inside the class are public.

Before we look at the remaining functions in our class, let's look at the JavaScript generated so far for our code. If you are following along then, to generate the JavaScript file, use Ctrl + Shift + B on Windows and Cmd + Shift + B  on macOS. This command will build the code and generate a corresponding JavaScript file. If we have the sourcemap flag turned on in our taskconfig.json then the build will generate another file with the name filename.js.map, which in our case is todo.js.map.

As we discussed earlier, for an interface, no code is generated, hence we just see the code for our two classes in the JavaScript file:

var Todo = (function () {
    function Todo(name, description, completed) {
        this.name = name;
        this.description = description;
        this.completed = completed;
   }
    return Todo;
}());
var TodoList = (function () {
    function TodoList() {
    }
    TodoList.prototype.createTodoItem = function (
                                        name, description) {
        var newItem = new Todo(name, description, false);
        var totalCount = TodoList.allTodos.push(newItem);
        return totalCount;
    };
    TodoList.prototype.allTodoItems = function () {
        return TodoList.allTodos;
    };
    return TodoList;
}());
TodoList.allTodos = new Array;

You will see that for both of our classes, the TypeScript compiler generated an immediately invoked function expression (IIFE) and assigned it to the variables Todo and TodoList respectively. An IIFE is a JavaScript function which is auto-executed when the JavaScript file is parsed. To identify the IIFE, look at the parentheses at the end of the function. The methods createTodoItem and allTodoItems are converted to prototype functions in JavaScript. The prototype is a JavaScript function which allows us to add behavior to our objects. In this case, the createTodoItem and allTodoItems functions introduce new behavior to the TodoList object. We had an allTodos static array in our TodoList class, which in JavaScript is just an array. 

Functions in TypeScript

The next function in our file is a window.onload function which is called when the browser is loaded.  The window.onload function is a standard JavaScript function and here is a good example of TypeScript being a superset of JavaScript. All JavaScript functions can be used directly in TypeScript. In the window.onload function, we just attach the event listener to the add button:

window.onload = function(){
    let name= <HTMLInputElement>document.getElementById("todoName");
    let description = <HTMLInputElement>document.getElementById(
                       "todoDescription");
    document.getElementById("add").addEventListener(
      'click',()=>toAlltask(name.value, description.value)); 
}

TypeScript allows us to type cast one type of value to another using <> or the as keyword. We will discuss this in more detail in later chapters; here, we should just know that document.getElementById returns a type of HTMLElement and, because we know that this element is a input element, we type cast that into HTMLInputElement. The last function, todoAllTask, is called every time we click and add a function, which takes a name and description entered by the user as input, calls the createTodoItem function of the TodoList class and then fetches the updated list of all Todo items and assigns that to a div using an ordered list. These two functions, when looked at in a JavaScript file, will be almost the same as what we wrote in TypeScript.

Debugging TypeScript code

Browsers don't understand TypeScript; they can only execute JavaScript code. That's why in our index.html file, we have a reference to todo.js and not to todo.ts. Our application is very small in size and it would not be difficult to debug the JavaScript code in the browser, but real-world applications are often large-scale with many files, each with hundreds of lines of code, and it would not be easy to debug the JavaScript generated by the TypeScript compiler. TypeScript provides a workaround to help developers debug their TypeScript code directly in the browser by using a special file with a .map extension. These are called source map files and we need to enable a flag in our tsconfig.json to allow the compiler to generate this file. The source map allows a relationship to be created between a JavaScript file and its corresponding TypeScript file. Once we generate the source map file, we can see the TypeScript file in our browser's source tab along with the JavaScript file.

In our code, we have already set the source map flag to true and you will see that the map file is generated when the compiler creates the JavaScript file. In the browser, press F12 on Windows or Cmd + Opt + I on macOS to open the developer tools. Then navigate to sources and you should see index.html, site.css, and an app folder. Inside the app folder, you should have both todo.js and todo.tsfiles. The following screenshot shows a snapshot of the developer tools in Chrome. On the left side is the list of files that were downloaded to the browser:

We can open the todo.ts file and add breakpoints; when the code is executed by the browser, our breakpoints will be hit and we will be able to debug the code therein. This makes it very easy for developers to debug the code that they have written rather than the code generated by the compiler.

 

Playground


The official TypeScript website provides a playground where you can write a TypeScript code and it will convert that to JavaScript code. You can also run the code and see the output in a new window. TypeScript has added samples as well, showcasing some of the features, such as Classes, Types, Inheritance, and Generics:

This is a very handy tool if you just want to try out TypeScript without getting into the details of creating a whole web application.

 

Summary


In this chapter, we gained an overview of TypeScript, and learned why TypeScript is such a popular language and what features make it so popular. We discussed what the problems of JavaScript are, and how TypeScript solves them.

We also did a step-by-step configuration of VS Code, which will be our IDE of choice.

In the next chapter, we will start digging deeper into some of the concepts of TypeScript by creating some real-life projects. 

About the Author

  • Sachin Ohri

    Sachin Ohri is a Technology Architect with a keen interest in web-based technologies. He has been writing web applications for more than a decade, with technologies such as .NET, JavaScript, Durandal, Angular, and TypeScript.

    He works on providing technical solutions, including architectural design, technical support, and development expertise, to Fortune 500 companies.

    He considers himself a polygot developer willing to learn new languages and technology. Recently, he has been focusing on cloud-based web application development with Microsoft Azure. He holds various Microsoft certifications, such as Microsoft Azure Architect, Microsoft ASP.NET MVC web application, and Microsoft Programming with C#.

    Browse publications by this author

Latest Reviews

(4 reviews total)
Dobré knihy za výbornou cenu.
I've not had time yet to review this book. It seems that it will be OK.
Excellent service. Easily navigated from search to checkout.
Book Title
Access this book, plus 7,500 other titles for FREE
Access now