Table of Contents
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).
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.
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.
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.
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.
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 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 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.
var num: number = 30;
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
|
var array: string[] = ['test', 'dummy'];
var first: string = array[0];
|
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
|
var name = { firstName: 'Homer', lastName: 'Simpson' };
name.firstName = 2;
|
JavaScript
|
var name = { firstName: 'Homer', lastName: 'Simpson' };
name.firstName = 2;
|
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 “lastName
” string
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.
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
|
var dummy;
var num = 10;
var str = 'Hello TypeScript';
var bln = true;
var stringArray = ['Homer', 'Simpson'];
|
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
|
var addFunction = function (n1: number, n2: number, n3: number) {
var sum = n1 + n2 + n3;
return sum;
};
var str1: string = addFunction(10, 20, 30);
var sum: number = addFunction(10, 20, 30);
var result = addFunction(10, 20, 30);
|
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:
var addFunction = function (n1: number, n2: number, n3: number) : number {
var sum = n1 + n2 + n3;
return sum;
};
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
|
var addFunction = function (n1: number, n2: number, n3?: number) : number {
var sum = n1 + n2 + n3;
return sum;
};
var sum: number = addFunction(10, 20);
|
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.
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
|
class Student {
private firstName: string;
private lastName: string;
yearOfBirth: number;
schoolName: string;
city: string;
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;
}
age() {
return 2014 - this.yearOfBirth;
}
printStudentFullName(): void {
alert(this.lastName + ',' + this.firstName);
}
}
|
JavaScript
|
var Student = (function () {
function Student(firstName, lastName, schoolName, city, yearOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.yearOfBirth = yearOfBirth;
this.city = city;
this.schoolName = schoolName;
}
Student.prototype.age = function () {
return 2014 - this.yearOfBirth;
};
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:
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.
var student = new Student('Tom', 'Hanks', 'World Acting School',1950);
var age = student.age();
var fullName = student.printStudentFullName();
var schoolName = student.schoolName;
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:
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.
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.
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.
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.
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.
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.
interface IStudent {
yearOfBirth: number;
age : () => number;
}
class College {
constructor(public name: string, public city: string) {
}
public Address(streetName: string) {
return ('College Name:' + this.name + ' City: ' + this.city + ' Street Name: ' + streetName);
}
}
class Student extends College implements IStudent {
firstName: string;
lastName: string;
yearOfBirth: number;
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 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.
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.
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.
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.
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.
<!-- 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
require.config({
baseUrl : "."
});
require(["bootstrapper"], (bootstrap) => {
bootstrap.run();
});
Bootstrapper.ts
import ds = require("DataService");
export function run() {
var service = new ds.DataService();
} alert(service.getMessage());
DataService.ts
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.
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 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:
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.
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:
export class DataService {
private videos: string[]
private moviesApiPath: string;
private categoriesApiPath: string;
private httpService: ng.IHttpService;
private qService: ng.IQService;
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();
}
}
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.
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