Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

TypeScript - 101: The Basics

4.82/5 (25 votes)
31 Jul 2014CPOL19 min read 122.1K   8  
The article intends to provide a jump start for web developers on TypeScript

Table of Contents

Introduction

TypeScript

Today, JavaScript is a universal web language, one language which is supported by every browser, does not need any special installation. No web development today is possible without using JavaScript and JavaScript has moved its wings not only to client side development but as well as to server side development like NodeJS. But, ask any developer who is learning JavaScript or coming from an Object Oriented background and they would roll their eyes when asked about how easy it is to do programming in JavaScript. One of the most powerful features of JavaScript is its dynamic type wherein we can assign anything to any variable but this feature itself becomes a roadblock in large scale JavaScript applications if we are not very careful. JavaScript also does not have a good IntelliSense and you will very rarely find errors at compile time, especially the type errors.

As stated on official TypeScript website, “TypeScript is a typed superset of JavaScript that compiles to plain JavaScript”. TypeScript is not a replacement of JavaScript, it does not add any new features in JavaScript. TypeScript provides developers with features like type safety, compile time type checking, object oriented constructs on top of JavaScript, basically lets developers think in object oriented terms when writing JavaScript. The most amazing thing about TypeScript is, it compiles in JavaScript so we don’t have to support any new VM to run TypeScript which then can be referenced in a web page, used in server side like in NodeJS.

TypeScript is an open-source developed by Microsoft, but is in no way tied to the Microsoft platform and can be used anywhere in any environment where there is a need to write JavaScript. Though Microsoft does provide a great support in Visual Studio for TypeScript and we will be using Visual Studio for our examples, but we can use TypeScript compiler as well from command prompt to compile TypeScript in JavaScript (we will see a brief example of that as well).

Installing TypeScript

TypeScript is included in Visual Studio 2013 Update 2 by default and can be installed for Visual Studio 2012 from installer provided on TypeScript website. Current version at time of writing this paper is 1.0. TypeScript also provides support for other editors like sublime, Emacs and Vim. TypeScript also has a package which can be used in Node.js. All these installations can be found on TypeScript

Once the TypeScript is installed for Visual Studio, it will add a new Project and Item templates. This enables us to create new project for TypeScript as well as add TypeScript files to existing applications.

Image 1

TypeScript file template can be created in a similar way as other files are, by selecting “Add New Item” and then selecting a TypeScript file.

All TypeScript files have *.ts extension. Visual Studio plugin for TypeScript automatically creates and updates a corresponding JavaScript file with the same name whenever we modify the TypeScript file and save. This generated JavaScript file can then be used as a normal file and included in any web page.

Image 2

When we create a TypeScript project, a default “app.ts” file gets created within the project which has a default code implementation. Visual Studio also provides a side by side view of TypeScript file with corresponding JavaScript file and every time we save TypeScript file, we can see the change in JavaScript file as well. TypeScript file achieves this feature by creating a corresponding “*.js.map” file. Visual Studio uses this map file to map the TypeScript code with the generated JavaScript code. Also, browser like Chrome uses these map files to help us debug TypeScript files directly instead of debugging JavaScript file.

Image 3

In case you see that automatically compiling TypeScript does not create or update JavaScript, check the options under Tool menu as shown below. This problem is used to come normally in TypeScript versions before 1.0.

Image 4

We can also generate JavaScript file from command line using “tsc.exe” command and passing <<filename>>.ts file, tsc.exe is available in “Microsoft SDK/TypeScript”.

TypeScript Fundamentals

TypeScript provides developers with object oriented concepts and compile time type checking on top of JavaScript which helps in writing more structured, maintainable and robust code. TypeScript introduces few of the standard object oriented terms like Classes, Interfaces, Module and Variables which in the end get converted into various different forms of JavaScript. The code structure for a typical TypeScript file is shown below.

Module

Module is like a namespace in the .NET world and can contain classes and interfaces. Modules do not have any feature of their own, they just provide a container which can be used to structure code in a logical form. Look at module just as a container of business/logical entity.

Interface

Interfaces are exactly like interfaces in .NET which provide a contract for the classes to implement. TypeScript helps in providing compile time error checking for the classes implementing these interfaces. If all the methods have not been implemented properly (including method signature), TypeScript flags those at design time as well as compile time. Interesting thing about Interfaces is that they do not exist in JavaScript and hence when we compile a TypeScript file into JavaScript, Interfaces are omitted.

Classes

The concept of Classes is again very similar to the .NET/Java world. Classes contains variables, properties and methods which form one logical entity. TypeScript also allows to set scope of the variable and functions with keyword like “private” and “public” though that scope does not have any effect on the JavaScript generated.

Functions

Functions are methods where the logic is implemented. TypeScript provides compile time support to make sure anyone calling the said function agrees to the input argument and return value type.

Variables

Variables are the fields defined inside a class or a function. TypeScript allows us to define a variable using keyword “var” and assign a data type to it. Once a data type is assigned, any further usage of the variable has to be with same data type, else TypeScript will generate error on design and compile time. TypeScript is also smart enough to infer the type of a variable and then treat it as that type when a variable is declared and initialized. In cases where TypeScript is not able to infer the type, it will assign that variable type of “any”.

TypeScript Types

TypeScript provides some primitive types (shown below) as well as a dynamic type “any”. “Any” is like “dynamic” keyword in C# wherein we can assign any type of value to the variable. TypeScript will not flag any type errors for variable of type “any”.

In TypeScript, we define a variable with a type by just appending the variable name with colon followed by the type name as shown in the below example.

C#
var num: number = 30; //variable num is of type number

Below is the list of primitive types available in TypeScript:

  • Number: The “number” is a primitive number type in TypeScript. There is no different type for float or double in TypeScript
  • Boolean: The “boolean” type represents true or false condition
  • String: The “string” represents a sequence of characters similar to C#
  • Null: The “null” is a special type which assigns null value to a variable
  • Undefined: The “undefined” is also a special type and can be assigned to any variable

 

Array Type: TypeScript also allows developers to create array objects similar to that in .NET by just adding square brackets as shown in the below example:

TypeScript

JavaScript

JavaScript
var array: string[] = ['test', 'dummy'];
var first: string = array[0];
JavaScript
var array = ['test', 'dummy'];
var first = array[0];
Table 1

This allows us to create a complex object in TypeScript with primitive types. In TypeScript, array is accessed with zero based index.

TypeScript also allows us to create complex variables as shown in the below example:

TypeScript

JavaScript
var name = { firstName: 'Homer', lastName: 'Simpson' };
name.firstName = 2; //This gives compile time error

JavaScript

JavaScript
var name = { firstName: 'Homer', lastName: 'Simpson' };
name.firstName = 2; //No Error in JavaScript
Table 2

Also, in the above case, notice that we had not defined the type of name variable, but TypeScript is smart enough to infer that name is a complex object with “firstName” and “lastNamestring variables and if we try to assign anything other than string to either of these variables, TypeScript will show a design time error with a red line below name variable.

Type Inference

As we saw above, TypeScript provides type inference wherein even if we don’t define a variable with a type, TypeScript infers the type with the value with which we would have initialized the variable. If we don’t initialize the variable nor we define a type when declaring a variable, TypeScript assigns “any” type to the variable. But, as JavaScript does not distinguish between any of these types, all the variables will be the same for JavaScript.

TypeScript

JavaScript
var dummy; //any type
var num = 10; //number
var str = 'Hello TypeScript'; //string
var bln = true; //boolean
var stringArray = ['Homer', 'Simpson']; //string[]

JavaScript

JavaScript
var dummy;
var num = 10;
var str = 'Hello TypeScript';
var bln = true;
var stringArray = ['Homer', 'Simpson'];
Table 3

Types are only valid for TypeScript and have no role in JavaScript generated. Types are just used by TypeScript for compile time checking and enable developers to make sure correct values are passed to variables.

Type checking is also available in functions. We can define types when defining the input parameters but, if type is not mentioned, TypeScript takes it as “any”. In case of return type, if we don’t define the type, TypeScript will infer the type depending on the use of those variables.

TypeScript

JavaScript
var addFunction = function (n1: number, n2: number, n3: number) {
var sum = n1 + n2 + n3;
return sum;
};
var str1: string = addFunction(10, 20, 30); //Gives compile time error as
     //return type of a function is number and is being assigned to a string

var sum: number = addFunction(10, 20, 30); // This works
var result = addFunction(10, 20, 30); // This also works

JavaScript

JavaScript
 var addFunction = function (n1, n2, n3) {
var sum = n1 + n2 + n3;
return sum;
};
var str1 = addFunction(10, 20, 30);
var sum = addFunction(10, 20, 30);
var result = addFunction(10, 20, 30);
Table 4

In the above table, we see that TypeScript uses type inference to determine that the “addFunction” has a “number” return type based on the input parameter types. When we try to assign the result of the function to a string variable, TypeScript gives a design and compile error. This does not happen in JavaScript which will compile properly. Also, if we would have not have defined type for variables “n1”, “n2”, “n3”, TypeScript would have assigned them “any” type and then it would have assigned return type as “any”. We can also explicitly define the return type by suffixing colon after the parameters and assigning the type, for example:

JavaScript
var addFunction = function (n1: number, n2: number, n3: number) : number {
var sum = n1 + n2 + n3;
return sum;
};

Optional Type

TypeScript also allows us to declare a variable in a function as optional so that anyone calling that function may or may not pass value for that variable. To make a parameter in a function as optional, we need to add “?” to the variable name. Again, optional parameters don’t exist in JavaScript and hence those will not be handled there.

TypeScript

JavaScript
var addFunction = function (n1: number, n2: number, n3?: number) : number {
var sum = n1 + n2 + n3;
return sum;
};
var sum: number = addFunction(10, 20);

JavaScript

JavaScript
var addFunction = function (n1, n2, n3) {
var sum = n1 + n2 + n3;
return sum;
};
var sum = addFunction(10, 20);
Table 5

Optional parameter has to be the last parameter in the list and there cannot be a required parameter after the optional similar to C# convention. We can also use optional concept in variables/fields defined in classes, shown in the next chapter.

Classes and Interface

Classes

TypeScript classes are a basic unit of abstraction very similar to C#/Java classes. In TypeScript, a class can be defined with keyword “class” followed by class name. TypeScript classes can contain constructor, fields, properties and functions. TypeScript allows developers to define the scope of variable inside classes as “public” or “private”. It’s important to note that the “public/private” keywords are only available in TypeScript, once it’s converted to JavaScript, there is no way to distinguish between the two and both can be called. TypeScript defines a constructor using keyword “constructor”.

TypeScript

JavaScript
 class Student {
    private firstName: string;
    private lastName: string;
    yearOfBirth: number;    //Public scope by default
    schoolName: string;
    city: string;
    //Constructor            
    constructor(firstName: string, lastName: string, schoolName: string, 
                city: string, yearOfBirth: number) {

        this.firstName = firstName;
        this.lastName = lastName;
        this.yearOfBirth = yearOfBirth;
        this.city = city;
        this.schoolName = schoolName;

    }
    //Function
    age() {
        return 2014 - this.yearOfBirth;
    }         
    //Function
    printStudentFullName(): void {
        alert(this.lastName + ',' + this.firstName);
    }
}

JavaScript

JavaScript
 var Student = (function () {
    //Constructor
    function Student(firstName, lastName, schoolName, city, yearOfBirth) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.yearOfBirth = yearOfBirth;
        this.city = city;
        this.schoolName = schoolName;
    }
    //Function
    Student.prototype.age = function () {
        return 2014 - this.yearOfBirth;
    };

    //Function
    Student.prototype.printStudentFullName = function () {
        alert(this.lastName + ',' + this.firstName);
    };
    return Student;
})();
Table 6

In the above constructor defined in TypeScript, we have few input variables which are then mapped to local variables inside a class, we can modify this constructor to implement implicit variable declaration and mapping by defining scope along with variable name in constructor definition as shown below:

JavaScript
constructor(private firstName: string, private lastName: string, public schoolName: string, 
            public yearOfBirth: number) {}

In the above case, variables now are defined and declared inside the constructor argument only. The scope mentioned along with the argument becomes the scope of the variable for that class.

To consume the class, the behavior is similar to C# where we use “new” keyword to initialize the class object, pass any parameters if the constructor requires and then call the functions or access public variables of the class.

JavaScript
var student = new Student('Tom', 'Hanks', 'World Acting School',1950);
 var age = student.age();
 var fullName = student.printStudentFullName();
 var schoolName = student.schoolName;

Default and Optional Parameter

In TypeScript, we can also define any parameter with a default value, and then when calling that function, we are not required to pass the value of those parameters. If we don’t pass the value, then the function takes the default value assigned, else the value passed in the function call is taken as shown in the example below:

JavaScript
constructor(private firstName: string, private lastName: string, public schoolName: string, 
            public yearOfBirth: number = 1990){}

In the above example, we have assigned an optional value to “yearOfBirth” field and if in case the calling function does not pass any value for this field, constructor will initialize this with 1990.

Similar is the case for Optional parameters, we can define a parameter by adding a “?” after the parameter name. In this case, when the function is called, we don’t need to pass the value for that parameter.

JavaScript
Subject(subjectList?: string[]) {
   if (subjectList == null) {
      alert('Oh, You have not subscribed to any course');
    }
  }

Here, if we call subject method without passing any parameter value, TypeScript will not show any error.

Interfaces

TypeScript offers support for Interfaces to use them as a contract for classes similar to C#. To declare an interface, we use keyword “interface” followed by the interface name. The important thing to know about interfaces is that when compiled in JavaScript, interface code is ignored and there is no corresponding JavaScript generated.

JavaScript
interface IStudent {
     yearOfBirth: number;
     age : () => number;
   }

Classes implement interfaces using keyword “implement” followed by interface name. As in C#, classes can implement multiple interfaces and TypeScript does a design time check to make sure that the class is implementing all the methods of that interface.

JavaScript
class Student implements IStudent

Here, Student class now will have to implement “age” method and define property “yearOfBirth” else TypeScript will show design time error with the error mentioning which property/method has not been implemented in the class.

Inheritance

Having classes and interface means TypeScript also supports inheritance which is a very powerful feature and aligns writing client side code to the way in which we write C# code. Using inheritance, we can extend classes, implement and extend interfaces and write code which very closely recognizes with OOPs. In TypeScript, when we extend a base class in child class, we use keyword “super” to call the constructor of base class or even the public methods of the base class.

To extend a class in TypeScript, we use “extend” keyword after the class name and then followed by the class through which we need to extend. We can also inherit interfaces on other interfaces.

JavaScript
//Interface
interface IStudent {
    yearOfBirth: number;
    age : () => number;
}
//Base Class
class College {
    constructor(public name: string, public city: string) {
    }
    public Address(streetName: string) {             
        return ('College Name:' + this.name + ' City: ' + this.city + ' Street Name: ' + streetName);
    }
}
//Child Class implements IStudent and inherits from College
class Student extends College implements IStudent {
    firstName: string;
    lastName: string;
    yearOfBirth: number;
    //private _college: College;
    //Constructor            
    constructor(firstName: string, lastName: string, name: string, city: string, yearOfBirth: number) {
        super(name, city);
        this.firstName = firstName;
        this.lastName = lastName;
        this.yearOfBirth = yearOfBirth;
    }
    age () { 
        return 2014 - this.yearOfBirth;
    }
    CollegeDetails() {
        var y = super.Address('Maple Street');
        alert(y);
    }
    printDetails(): void {
        alert(this.firstName + ' ' + this.lastName + ' College is: ' + this.name);
    }
}

Modules

Modules in TypeScript have similar purpose as namespaces in C#, it allows us to group together logical code. Modules help us to follow “separation of concerns” concept in client side code wherein each module can have a specific role. Modules provide us with the flexibility by allowing us to import other modules, export features outside modules.

Everything inside of a module is scoped to that module hence, the classes and interfaces placed inside a module cannot be accessed outside until we explicitly provide scope for them with keyword “export”.

Modules are declared using “module” keyword. We can nest one module inside another module which can help us provide better code maintainability.

JavaScript
module Movie {
    class Comedy {
        constructor(public actorName: string) { }

        getAllMovies() {
            return (["Alien", "Paul Bart", "Home Alone"]);
        }

        getMoviesbyActor() {
            if (this.actorName === 'Seth Rogen') {
                return (["Observe and Report"]);
            }
            else {
                return (["Home Alone"]);
            }
        }
    }   
}

Here, we have declared a module which has a class defined in it. The interesting thing to note is that the class “Comedy” is not visible outside the module “Movie” but can be accessed inside the “Movie” module as it's in that scope. This helps in separation of code and provides relevant scope as per business needs.

To be able to access classes, interfaces or variables outside a module, we need to mark those with keyword “export”. Once a class inside a module is marked with “export” keyword, all the public variables, functions are also accessible outside the module.

Hence, modules help us with minimizing the scope of classes and provides us with the more robust platform to manage client side code. In any application irrespective of the size of the application, we would want to access modules inside other modules, get a reference, call the methods inside classes and so forth. To achieve this, we would need to create dependencies between modules and make sure that the scripts are loaded on a page based on the dependencies, a module which is not dependent on any other module should be loaded first and so on.

In TypeScript, we have two ways to add dependencies between modules as explained in the following sections.

Referencing Internal Modules

TypeScript provides a system (this mechanism is also available in Visual Studio for JavaScript) by which we can make modules available inside other modules and even throughout the program. This can be achieved using reference comments on top of the module in which we want to reference other module. The dependencies for any module are defined on top of that module in the form of comments.

JavaScript
/// <reference path="Sample.ts" />
  var college = new Sample.College('My College', 'My City');

Above, we see that on adding a reference to Sample module (which is inside Sample.ts), we are able to access College class, provided College class is marked with “export” keyword. Reference comments can be added by just dragging and dropping a file, Visual Studio by default will add these comments on top of the file.

The reference comment informs compiler that the Sample module will be available before this module loads and hence compiler allows classes inside Sample module to be accessed here. By adding “reference” comment, we also get auto-completion and design time compile checking for the classes. We can add as many “reference” comments as we need to add dependencies for a module.

With this approach, we should be aware of the dependencies graph for each module and hence it is suitable for small or medium size applications. We have to make sure that all the dependencies are loaded before the specified module to make it work and this can cause major headache for large applications where there are numerous modules and their respective files.

Asynchronous Module Definition (AMD)

AMD allows modules to be loaded asynchronously on need basis. RequireJS is one such library which provides the mechanism to load modules on demand. We just need to reference dependent modules using keyword “import” and RequireJS takes care of loading them at runtime. AMD manages the dependencies for each module and takes away the complexity of making sure all the dependent modules are loaded on the page before the specific module. RequireJS uses the concept of identifying who is dependent on whom and then loading them in that sequence.

This is a very useful technique for large scale web applications where we have lot of TypeScript/JavaScript files and it is a headache to maintain the dependency graph.

RequireJS handles module loading using configuration style programming. Rather than loading all the scripts in the specific order, using RequireJS, we just define a startup/bootstrap file in our HTML page. RequireJS reads that and navigates to the startup file which would then as required call other modules as and when we call other modules, RequireJS loads the dependencies on demand.

JavaScript
<!-- Below line initalizes requirejs and mentions the startup file. In this case main-->
   <script data-main="main" src="Scripts/require.js" type="text/javascript"></script>

Then in main.ts/main.js, we define the start method in this case run() which would be responsible for loading start page, in this case a dataService.

main.ts

JavaScript
require.config({
    baseUrl : "."
}); 

require(["bootstrapper"], (bootstrap) => {
    bootstrap.run();
});

Bootstrapper.ts

JavaScript
import ds = require("DataService");

export function run() {
    var service = new ds.DataService();
}    alert(service.getMessage());

DataService.ts

JavaScript
export interface IDataService {
     msg: string;
     getMessage(): string;
    };

export class DataService implements IDataService {
     msg = 'Data from API Call';
     getMessage() { return this.msg; }
}

In summary, managing many TypeScript/JavaScript files is an important task which needs to be planned beforehand. For small scale applications, managing dependencies is not a major concern as we can just “reference” style comments and make sure we load scripts in the defined order. But, if we know that the application is going to grow to large number of files, then we should plan to have dependencies managed properly.

TypeScript with External Libraries

In the above chapters, we have seen how TypeScript wraps the ugliness of the JavaScript in object oriented goodness, now it’s time to extend this goodness and add a little sweetener in it.

In today’s day and age, it’s quite frequent to use external libraries for client side development, to name a few famous ones Jquery, Knockout, Toastr and most famous of them all Angular. TypeScript has a role to play with these libraries as well, it allows us to use these libraries as a reference in our TypeScript code using “Ambient Declarations”.

Ambient Declarations

Ambient declaration is a way by which TypeScript provides all its features like autocompletion, type checking, design and compile time type safety for external libraries. TypeScript comes preloaded with definitions of DOM (document object model) and JavaScript APIs for example:

JavaScript
window.onload = function () {
     var t: HTMLElement =    document.getElementById('id'); }

Here, we see that in TypeScript, if we type in “document” we get intellisense for all the methods available with “document”. This helps us in writing native JavaScript in TypeScript and make sure that we are following the correct structure for each method call.

TypeScript also has support for other popular libraries using their respective definition files. These files have an extension of “*.d.ts” and are used by TypeScript to add design time support and compile time checking. These files just contain the definition of all the functions supported by the library and does not have any implementation. All the libraries are available at TypeScript Definitions. To access these libraries, we just need to include their corresponding “*.d.ts” using “reference comments”. Once we have included this file, we will have access to the libraries classes and function for example if we include Jquery.d.ts file, we will have access to “$” function and TypeScript will also provide intellisense for all the Jquery functions.

JavaScript
/// <reference path="typings/jquery.d.ts" />
    document.title = 'Hello TypeScript';
    $(document).ready(function() {
    var v;
    });

Similarly, we can use definition files of Angular to write client code in TypeScript, sample shown below:

JavaScript
/// <reference path="../scripts/typings/angularjs/angular.d.ts">
/// <reference path="../scripts/typings/angularjs/angular-route.d.ts">

export class DataService {
        private videos: string[]
        private moviesApiPath: string;
        private categoriesApiPath: string;
        private httpService: ng.IHttpService;  //Note the type ng.IHttpService
        private qService: ng.IQService;        //Note the angular promises

        getAllMovies(fetchFromService?: boolean): ng.IPromise<any> {
            var self = this;

            if (fetchFromService) {
                return getMoviesFromService();
            } else {
                if (self.movies !== undefined) {
                    return self.qService.when(self.videos);
                } else {
                    return getVideosFromService();
                }
            }

Summary

For each of the features in TypeScript, we have been relating to corresponding features in OOPs language such as C# and Java but, we need to keep in mind that TypeScript is not a OOPs language. In fact, TypeScript is just a tool on top of JavaScript which provides us with more robust code structure, type safety. TypeScript enhances the productivity of developers writing JavaScript code and it in itself does not provide any specific functionalities or features like libraries such as Jquery.

Most of the features which we use in TypeScript gets removed from the compiled JavaScript file and we are left with nothing more than a pure JavaScript code. TypeScript is open source and is no way tied to Microsoft or .NET technologies. Developers writing code in JavaScript can use TypeScript with various different IDEs apart from Visual Studio like Sublime Text, VIM. There are various forums/blogs available on TypeScript and the development community has started to use TypeScript with their respective libraries. Resharper is also providing support for TypeScript in its Version 8 release which allows developers easier path to refactor, create functions and other features which Visual Studio users are so accustomed to use.

Appendix

Reference Websites for TypeScript

Reference Websites for RequireJS

Reference Website for TypeScript with Angular

Reference Website for Resharper

Contact Me: You can contact on twitter @ohri_sachin

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)