TypeScript: A strict typed language for JavaScript world

TypeScript is a free and open-source typed superset of javascript(in other words ECMAScript 2015) that compiles to plain javascript. So every javascript program is a valid typescript code. The typescript can be used in both client side and server side javascript applications. Actually it is meant for developing large scale applications where you can get the huge benefit of typescript.The typescript compiler itself is written in Typescript code. The static language analysis will bring tooling and IDE support.

There are two ways to install typescript tools

  1. Using npm (a node package manager)
npm install -g typescript

2. Using Typescript’s visual studio plugins

If you are using either Visual Studio 2017 or Visual Studio 2015 Update 3 then it include TypeScript by default. And if you are using older versions then you need to download it separately.

Write your first Typescript file:

Let’s first create a greeting function which accepts a String type and file name as greeting.ts( with ts extension).

function greeting(msg: string) { return "Hello,  Welcome to " + msg; }

let msg = "TypeScript";

document.body.innerHTML = greeting(msg);

After that run the typescript compiler to convert TS code to JS code

tsc greeting.ts

It creates greeting.js file and display the message in console. Remember that, the typescript types won’t exist in generated in javascript.

Building Blocks:

Basic Types:

Any programming language need to deal with some of the simplest units of data: numbers, strings, structures, boolean values,

Boolean:

The boolean type declaration is similar to javascript with type defined

let isVerified: boolean = false;

Number:

Just like javascript, all number in typescript are floating point values.It supports decimal and hexadecimal literals along with newly added octal and binary literals supported in ES6.

let decimal: number = 6;
let hex: number = 0xfabcd;
let binary: number = 0b0101;
let octal: number = 0o4744;

String:

The Strings are fundamental elements in any programming language and even it applied for TypeScript as well. Just like Javascript, the strings are represented in either single or double quotes.The multiline embedded expressions(using ${} form) known as template strings are supported.

let firstname: string = 'Sudheer';
let lastname: number = 'Jonna';
let sentence: string = `Hello, my name is ${ firstname } ${lastname}.`

Array:

You can represent arrays in two ways. That is, either represent the type followed by [] notion or use a generic type array(Array<Type>)

let list1: number[] = [1, 2, 3, 4, 5];
let list2: Array<number> = [1, 2, 3, 4, 5];

Tuples:

Typescript also supports tuples, it is similar to arrays but accepts different types of data.

let x: [string, number];
x = ["typescript", 2]; // OK
x = [2, "typescript"]; // Error

If you access an element with a known index then correct type is retrieved. And if you try to access an element outside of the indices then union type is used instead.

console.log(typeof x[0]) //String
console.log(typeof x[1]) //Number

x[2]= "Welcome";//Ok
x[3] = true// Error

Enums:

Typescript additionally supports Enum type which exist in most of the programming languages except javascript. It assigns meaningful names to the numeric values. The characteristics of enum type is similar to other programming languages.

enum Months{JAN, FEB, MAR}// Defaults to zero
console.log(Months.MAR); //Displays 2
console.log(Months[1]); //Displays FEB

enum Color {Red = 2, Green = 5, Blue = 9} //Assign specific values
let c: Color = Color.Green;
console.log(c);// 5

The dynamic nature of javascript is applicable in typescript using any type. It is useful to accept all types of data if you don’t know the exact type. Due to that it pass the compilation check without verifying the type. It is different from Object type which has specific set of methods and properties. Also you can use it as heterogeneous array.

let random: any = 4;
random = "hello ts user";
random = true; 

random.test()// no issue
let randomObj: Object = 4;
randomObj.test()// fails as it don't has test method

let randomArray: any[] = [1, "ts"", true];

Void:

In contrast, the opposite of any type is void. It means absence of particular type which is normally used for function return type. But if you use it for variable declaration then it accepts either undefined or null.

function greeting(): void {
   alert("Hello TS user");
}
let notdefined: void = undefined

Unused:

To represent unusable entities similar to void, there are two more types named null and undefined. These types are subtypes of all typescript types.i.e, any type of data can be assigned with null and undefined. But if you enable strictNullChecks then only null, undefined and void types accepted for these types.

let unused1: undefined = undefined;
let unused2: null = null;

Never:

There is one type called ‘never’ which is used to represent an error expression or the code that never returns.

// Function returning never must have unreachable end point
function error(message: string): never {
    throw new Error(message);
}
// Inferred return type is never
function fail() {
 return error("Something failed");
}
// Function returning never must have unreachable end point
function infiniteLoop(): never {
  while (true) {}
}

Interfaces:

Interfaces are helpful to define contracts(shape that values have) with in your code. For example, the below interface gives the shape for booking ticket and able to access the required property by checking the property name.

interface booking {
   moviename: string;
}
function bookticket(booking: bookingObj) {
  console.log(bookingObj.moviename);
}

let bookingObj = {price: 20, moviename: "Thor"};
bookticket(bookingObj);

The optional parameters gives the information on possible of available properties while preventing the usage of properties that are not part of interface. It is just similar to normal interface except that denoted by ? symbol after property name.

interface booking {
  moviename?: string;
  price?: number;
}
function bookticket(booking: bookingObj): {moviename: string, price: string} { 
let newBooking = {moviename: "Thor", price: 10}; 
if (bookingObj.moviename) { 
    newBooking.moviename = bookingObj.moviename; }
 if (bookingObj.price) { 
    newBooking.price = newBooking.price + 2; // Service tax 
  } return newBooking; 
} 
let newBooking = bookticket({moviename: "Avengers"});

The readonly parameters prevents modifying the properties similar to const on variables.

interface Car {
    readonly brand: string;
    readonly year: number;
}

let car: Car = { brand: 'Audi', year: 2005 };
car.brand = 'Benz'; // error!

Also it provides ReadonlyArry<T> similar to Array<T> by removing the mutating methods,

let nums1: number[] = [1, 2, 3, 4];
let nums2: ReadonlyArray<number> = nums1;
nums2[0] = 12; // error!
nums2.push(5); // error!
nums2.length = 100; // error!
nums1 = nums2; // error!
nums1 = nums2 as number[];

Classes:

JavaScript follows functions and prototype based inheritance to reuse the components where as typescript goes one level more by introducing classes concept from object oriented programming. Starting from ES7 all browsers supports classes and objects where as Typescript provided them by converting to respective JS code.

For example, let us take vehicle and car classes and their relationship. The parent Vehicle class has properties and methods and child class inherit them along with it’s own behavior.

class Vehicle {
     licensePlate(license: string) {
         console.log(`Vehicle license details are: ${license}.`);
     }
class Car extends Vehicle {
    numberOfSeats(seats: number = 0) {
          console.log(`No. of seats are ${seats}`);
     }
}
const car = new Car();
car.numberOfSeats();
car.licensePlate('One motoring');
car.numberOfSeats();

The classes supports modifiers(public, private and protected),abstract classes, static properties and so on features from object oriented programming concepts.

Functions:

Similar to javascript, typescript functions can be created both as a named or anonymous functions based on application type. Typescript adds type for each part of the function as below.

// One
function add(a: number, b: number): number {  
    return a + b;
}
// Two
let calculate = function(a: number, b: number): number { return a + b; };
// Three
let calculate: (a: number, b: number) => number =
    function(x, y) { return x + y; };

In some cases, typescript compiler can figure out the type if you have types on one side of the equation but not the other. This is helpful to reduce the efforts while creating the typed program. For example,  the third example rewritten without the return type as below,

let calculate: (a: number, b: number) => number =
     function(x, y) { return x + y; };

Unlike javascript, typescript is very strict on number of parameters passed and it throws an error if the parameters didn’t match. Actually javascript is dynamic by allowing any number of parameters by treating remaining parameters as undefined. This behavior is achieved through optional parameters using question(?) mark on the parameter. On the other hand default values provided to the parameters by assigning the values directly.

function fullName(firstName: string, lastName?: string) {
    return firstName + lastName
}
function fullName(firstName: string, lastName='jonna') {
    return firstName + lastName
}

You can also define group of parameters as rest parameters using eclipse(…) before the parameter name. It is useful to group any number of optional parameters. This behavior is similar to arguments to hold the parameters inside the body of javascript function.

function namesList(firstName: string, ...remainingNames: string[]) {
   return firstName + " " + remainingNames.join(" ");
}

TypeScript also has overloading feature similar to any object oriented programming language.

Generics:

Generics are common in programming languages such as c# and Java to reuse the components across the application. If you use specific type then it can’t be reused and if you any type then you will loose the type information. Considering this, the generics are supported and represented by type variable(T).

For example, if we pass age parameter to profile function which returns the same argument as output then we will loose the type information from return type.

function profile(age: any): any {
    return age;
}

We can prevent this with the help of generics as below,

function profile<T>(age: T): T {
    return age;
}

Normally, we call the above functions with type information in the form of angular brackets(<Number>) or without explicit type information using type inference(decided by compiler).

let profile = profile<Number>(30);

let profile = profile(30); // Infer

Enums:

The numeric enums are common in many programming languages with auto-incrementing behavior. You can also initialize the first value in order to change the default value of zero. Whereas String enums are used to give meaningful and readable names. It is also possible to have heterogeneous members which has mixed string and numeric enums but it is rarely used..

enum Months {
  JAN,
  FEB,
  MAR,
  APR
}
enum Months1 {
  JAN = 1,
  FEB,
  MAR,
  APR
}
enum Months2 {
  JAN="JAN",
  FEB="FEB",
  MAR="MAR",
  APR="APR"
}
enum Heterogeneous {
    Yes="YES",
    No=0
}

Type Inference:

TypeScript provides type information whenever the explicit type annotation is not specified. This applies for 3 different types: basic types, best common types and contextual type.

  1. Basic: If you use any primitives value representations then the type of the entity achieved easily. For example,  if you define the variable with number value without any type information then type is inferred as Number type automatically.

let a = 100 // Inferred as number type

2. Best Common Type: If the type is inferred from several expressions then best common type which satisfies all the expressions treated as type of the output. For example, if you have an array of Car,Bus and Bike as values. It is not possible to infer the type due to various types which don’t have common or super type among them. So either explicitly define Vehicle type or provide the union type.

let vehicles = [new Car(), new Bus(), new Bike()]
Solution1: let vehicles: Vehicle[] =[new Car(), new Bus(), new Bike()] 

Solution2: let vehicles: Car | Bus | Bike =[new Car(), new Bus(), new Bike()]

3. Contextual Type: In some of the cases, the type of the expression is decided by the contextual information. For example, typescript takes the help of  expression window.onkeyup  to infer the keyup event parameter of the right hand side function.

window.onkeyup = function(keyEvent) {
   console.log(keyEvent.button);
};

So the type of the parameter is inferred as KeyEvent

Dynamic vs Static typing:

Javascript is a dynamic language which gives more flexibility to the language and it is the core principle of its evolution. Due to this nature, we can easily add the properties to the objects and pass various kinds of data between the methods without worrying about the type of data. Whereas Typescript brings type system to the javascript world to avoid the bugs in the runtime by identifying the issues in the compile time. Also it makes the ease of creating the development tools. TypeScript got more popularity once it announced as scripting language for Angular2 framework.  Some argue that it kills the javascript dynamic behaviors and less impact on reducing the bugs but few other argue that it brings robustness to the applications with strict typing.

Conclusion: 

TypeScript boost the productivity of web development due to it’s ECMA 2016 syntax and optional typing features. The learning curve is less due to similar syntax of JavaScript and considering every javascript code snippets as a valid typescript code. The popularity is increased with the usage especially in Angular development. If you come from Object oriented programming background then most of the features are not new anymore.

 

Leave a Reply

Your email address will not be published. Required fields are marked *