TypeScript – A Primer

13 / Oct / 2016 by Ravi Shankar Tiwari 0 comments

The evolution of JavaScript from merely a scripting language to a general purpose programming  language is indicative of the Atwood Law. JavaScript is a multi-paradigm object based language with roots in C, Java, Self and Scheme. It was designed to be relaxed i.e. without a static type system. This in my opinion is a perfect rationale for a scripting language –  more so if you are designing such a thing in weeks time; my respect to Brendan Eich.

However, the web today is not the same as it was before and evolution demands civilization. TypeScript is Microsoft’s forte for JavaScript’s civilization, adding nothing more but syntactic sugar – developers on insulin be fore warned – for static typing to meet the need(s) (Microsoft does not provide reference to this need!) of JavaScript teams that build and maintain large scale JavaScript applications.

This blog is a primer to TypeScript, just enough sugar to make you mobile – not agile – so that you can, like me, understand the code written by other in TypeScript, and write your own code too. So let’s begin.

It’s all about types

Types in TypeScript are an extension over that provided by JavaScript. We have

  • boolean for booleans
  • number for numbers – decimal, hexa, octa, binary
  • string for strings
  • enum for enumerative values
  • any for unrestrictive type and many more …

We annotate a variable with its type while declaration. The grammar for this construct is <scope identifier> <variable identifier> : <type identifier>. Here’s how we do that in code:

 ------ scope identifier (e.g. var, let)
|    	 ------ variable identifier
|   	| 		 	  		 ------ type identifier
|   	| 			 		|
var isJavaScriptAwesome: boolean;
const withoutAnyDoubt: boolean = true;
let isTypeScriptASuperSetOfJavaScript : boolean = false;

function echo(sayTheWords: string) {
	// All (wo)men must die!
}

echo('Valar Morghulis');

isJavaScriptAwesome = withoutAnyDoubt;
// This will be a TypeScript compiler error though
isJavaScriptAwesome = 20

Although the last statement is a compiler error, it will be processed and a valid JavaScript file will be generated as there is no notion of types inherent to the language. However, this definitely help developers in discovering and avoiding author time errors that previously were discoverable only during run time.

We can similarly define the structure of our JavaScript code through TypeScript’s rich type vocabulary. The TypeScript compiler will try to infer the structure of JavaScript code and provide valuable hints, tooling in terms of intellisense, code-completion, warnings and/or error etc, through mechanism dubbed as duck typing. Here’s how we can define type for an object using interfaces provided by TypeScript.

/**
Defining structure for a Person object. The object:
 - must have a `name` key which can only be assigned a string values
 - can have an optional(see ? mark) `age` key of type number
 - must have an `address` key the type of which is not known or not restricted by the compiler
*/

interface Person {
	name: string,
	age?: number,
	address: any
}

// defines a function that accepts an argument of type Person
function displayPersonInfo(person: Person) {
	// logic to do the magic
}

var p: Person = {
	name: 'Mr X in Bombay',
	address: [
		'A deprecated steet',
		'on lonesome locality',
		'in the vicinity of',
		'erstwhile Bombay'
	]
}

displayPersonInfo(p);

// we can also write
displayPersonInfo({
	name: 'Rocket Singh',
	age: 40,
	address: {}
});

// this is error, required parameter missing
displayPersonInfo();

// this too, this aint quack like a duck!
displayPersonInfo({
	firstName: 'Rocket'
});

Now that we have seen a glimpse of the TypeScript’s vocab, here are some common use cases.

Defining variable types

let amIDumb: boolean = true;
let binaryDecision: number = 0b01;
let whatIsTheColorOfSky: string = 'blue' // are you sure?

const theNinjas: string[] = ['Doug Crockford', 'Kyle Simpson', 'John Resig'];
const theSamurais: Array<string> = ['Ryan Dhal', 'Misko'];

var assignMeAnything: any = 'Typeless in a typed world';
assignMeAnything = {};
assignMeAnything = [];
assignMeAnything = 3.14159;

let deVoid: void = null; // null and undefined are void types
deVoid = undefined;

Defining enums

enum TrafficSignal {
	Green,
	Yellow,
	Light
}

let signal: TrafficSignal;

... // some code

if ( signal === TrafficSignal.Green) {
	// good to go
} else {
	// don't risk life over triffle things
}

Defining types for functions

function funcAlias(argument: type) : returnType {

}

function squareInt(input: number) : number {
	return input * input;
}

Defining structure through interfaces

  • Type for objects

    interface Point {
    	x: number,
    	y: number
    }
    
    function printCoordinates(point : Point ) : void {
    	let pointStr = `(${point.x}, ${point.y})`;
    	console.log(pointStr);
    }
    
  • Type for functions

    // a function that works with type T and return boolean; remember generics
    interface Predicate<T> {
    	(item: T) : boolean
    }
    
    // a function that takes an array of T and a predicate of T
    // and return an array of T
    interface Filter<T> {
    	(collection: Array<T>, predicate: Predicate<T> ) : Array<T>;
    }
    
    let isEven: Predicate<number>;
    isEven = function (arg: number): boolean {
    	return (arg & 1) == 0;
    }
    
    let getEvens: Filter<number>;
    getEvens = function(collection: number[], predicate: Predicate<number>) {
    	return collection.filter(isEven);
    }
    
    console.log( getEvens([1,2,3,4,5,6,7], isEven) );
    

Similarly we can define interfaces for advanced structures like classes, but that would be too much for a primer. So enjoy the a la carte and I promise will serve the meal soon.

Do let me know your opinions in the comments.

FOUND THIS USEFUL? SHARE IT

Leave a comment -