Skip to content

Instantly share code, notes, and snippets.

@robfe
Last active December 16, 2015 20:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robfe/5493122 to your computer and use it in GitHub Desktop.
Save robfe/5493122 to your computer and use it in GitHub Desktop.

TypeScript (0.8)

  • A superset of the JavaScript language.
  • Code in TypeScript, compile to JavaScript, deploy JavaScript. (Similar workflow to CoffeeScript)

Advantages

  • Very similar to JavaScript.
  • Type safety - when you need it. TypeScript is a gradually typed language.
  • Less boilerplate.
  • Programmer's intent is clearer in the code.
  • Easy to start using: Install the compiler, turn on filewatcher, rename a *.js file to *.ts and add type markup at your lesiure.
  • Easy to stop using: Delete the *.ts file, continue editing the *.js file.

How to get it

http://www.typescriptlang.org/#Download

The Language

Type Checks

Primitives

A primitive type is a number, bool, string or void.

Before type check:

function showSum(x, y){
    alert(x + " + " + y + " = " + (x+y));	
}

showSum(5, "7");

This is an ordinary peice of JavaScript. But it doesn't work as intended.

With type check:

function showSum(x : number, y:number){
    alert(x + " + " + y + " = " + (x+y));	
}

showSum(5, "7");

By adding the type annotation, the programmer's intent is clearer, and the compiler can check if the right arguments are being passed.

Interfaces

Creating an interface for the argument to showSum:

interface Addends{
    x:number;	
    y:number;
}

function showSum(a:Addends){
    alert(a.x + " + " + a.y + " = " + (a.x + a.y));	
}

showSum({y:2, x:5});

An interface is a type that defines the property names expected on an object instance (and their types).

Classes

A class is also a type. There is an example of this later.

Syntactic sugar

There are a number of ways in which TypeScript helps reduce the amount of code you have to type:

Arrow Function Expressions

Functions can be declared shorthand:

interface Addends{
    x:number;	
    y:number;
}

var showSum = (a:Addends) => alert(a.x + " + " + a.y + " = " + (a.x + a.y));

showSum({y:2, x:5});

You can stop typing "function" so much! Multiple arguments and statements are supported:

var alertBoth = (s1:string, s2:string) => {alert(s1);alert(s2);};

Class Definitions

Class declarations are a formal part of the language. TS generates the appropriate JS:

class Adder {
    x : number;
    y : number;

    constructor(x:number, y:number){
	    this.x = x;
	    this.y = y;
    }

    getSum(){
	    return this.x + this.y;
    }

    showSum(show : (string)=>void){
	    show(this.x + " + " + this.y + " = " + this.getSum())
    }
}

var a = new Adder(2, 3);
a.showSum(s => alert(s));

This declared a class named "Adder" with the fields x and y, and a constructor that set these fields, and two methods, getSum and showSum. Note the equivalent javascript that TS generates.

Modules

The "module" keyword creates a namespace:

module Mathematics{
    export class Adder {
	    x : number;
	    y : number;

	    constructor(x:number, y:number){
		    this.x = x;
		    this.y = y;
	    }
	
	    getSum(){
		    return this.x + this.y;
	    }
	
	    showSum(show : (string)=>void){
		    show(this.x + " + " + this.y + " = " + this.getSum())
	    }
    }
}

var a = new Mathematics.Adder(2, 3);
a.showSum(s => alert(s));

The compiler has an AMD mode too!

OOP

Abstraction

There are no formal abstract classes or methods in TypeScript, but you can create a method whose base implementation throws.

Encapsulation

There are properties and "private" fields:

class Adder {
    private x : number;
    private y : number;

    constructor(x:number, y:number){
	    this.x = x;
	    this.y = y;
    }

    get sum(){
	    return this.x + this.y;
    }

    showSum(show : (string)=>void){
	    show(this.x + " + " + this.y + " = " + this.sum)
    }		
}

var a = new Adder(2, 3);

//compiler warning, runtime set value
a.x = -10;

a.showSum(s => alert(s));

Inheritance

Classes can extend other classes:

class Operation {
    x : number;
    y : number;
    operatorText:string;

    constructor(x:number, y:number, operatorText:string){
	    this.x = x;
	    this.y = y;
	    this.operatorText = operatorText;
    }	

    operate():number{
	    throw "abstract method not implemented";
    }

    showOperation(show : (string)=>void){
	    show(this.x + " " + this.operatorText + " " + this.y + " = " + this.operate())
    }	
}

class Subtractor extends Operation {		
    constructor(x:number, y:number){
	    super(x, y, "-");
    }

    operate(){
	    return this.x - this.y;
    }
}

var a = new Subtractor(11, 4);

a.showOperation(s => alert(s));

This created a class named Operation, which holds some fields and knows how to show itself, and a class named Subtractor which extended Operation to provide specific implementation details.

IMO, one of the most disappointing aspects of TS is how you can't use another framework's own special brand of inheritance.

Polymorphism

Polymorphism can be class based:

class Operation {
    x : number;
    y : number;
    operatorText:string;

    constructor(x:number, y:number, operatorText:string){
	    this.x = x;
	    this.y = y;
	    this.operatorText = operatorText;
    }	

    operate():number{
	    throw "abstract method not implemented";
    }

    showOperation(show : (string)=>void){
	    show(this.x + " " + this.operatorText + " " + this.y + " = " + this.operate())
    }	
}

class Subtractor extends Operation {		
    constructor(x:number, y:number){
	    super(x, y, "-");
    }

    operate(){
	    return this.x - this.y;
    }
}

function alertOperation(o:Operation){
    o.showOperation(s => alert(s));
}

alertOperation(new Subtractor(11, 4));

The alertOperation function can take any class that inherits from Operation, and we're providing it with a Subtractor.

Polymorphism can be interface based:

interface CanShowOperation{
    showOperation(show : (string)=>void);
}

class Operation implements CanShowOperation {
    x : number;
    y : number;
    operatorText:string;

    constructor(x:number, y:number, operatorText:string){
	    this.x = x;
	    this.y = y;
	    this.operatorText = operatorText;
    }	

    operate():number{
	    throw "abstract method not implemented";
    }

    showOperation(show : (string)=>void){
	    show(this.x + " " + this.operatorText + " " + this.y + " = " + this.operate())
    }	
}

class Subtractor extends Operation {		
    constructor(x:number, y:number){
	    super(x, y, "-");
    }

    operate(){
	    return this.x - this.y;
    }
}

function alertOperation(o:CanShowOperation){
    o.showOperation(s => alert(s));
}

alertOperation(new Subtractor(11, 4));

The alertOperation function can take any object that implements the properties of the CanShowOperation interface, and we're providing it with a Subtractor. Note that Operation doesn't have to explicitly implement CanShowOperation.

Type Definition References

Type Definition files (*.d.ts) are for holding definitions but not implementations. They are usually used to create TS definitions for existing JS code. For example, here's the type definitions for Underscore.

It's often handy to pull in some definition files for the library you're using. Definitely Typed is a good one.

The future

0.9 Alpha has just come out. It features:

  • Generics (just like java or C#)

  • Constant overloads

      interface Document {
          createElement(tagName: string): HTMLElement;
          createElement(tagName: 'canvas'): HTMLCanvasElement;
          createElement(tagName: 'div'): HTMLDivElement;
          createElement(tagName: 'span'): HTMLSpanElement;
          // + 100 more
      }
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment