Sample Code for TypeScript Article in Windows.Developer Magazine

Friday, November 2, 2012 by Rainer Stropek

I am currently writing an article about TypeScript for the upcoming issue of the German Windows.Developer magazine. It contains a larger code sample demonstrating some key concepts of the new language. Some readers might be interested in playing with the sample code in TypeScript's Playground. Probably they do not want to type in the sample code. Therefore I publish the code in this article.

OO Concepts in TypeScript

The first sample deals with the TypeScript language. It demonstrates some OO concepts of the language:

// Define a top-level module
module CrmModule {
  // Define an interface that specifies what a person must consist of.
  export interface IPerson {
    firstName: string;
    lastName: string;
  }
  
  // Note that Person would not need to specify "implements IPerson" 
  // explicitely. Even if the "implements" clause would not be there, 
  // Person would be compatible with IPerson because of structural subtyping.
  export class Person implements IPerson {
    private isNew: bool;       // a private member only accessible inside Person
    public firstName: string;  // a public member accessible from outside
    
    // Here you see how to define a constructor
    // Note the keyword "public" used for parameter "lastName". It 
    // makes "lastName" a public property. "firstName" is assigned manually.
    constructor(firstName: string, public lastName: string) {
      this.firstName = firstName;
    }
    
    // A public method...
    public toString() {
      return this.lastName + ", " + this.firstName;
    }
    
    // A public get accessor...
    public get isValid() {
      return this.isNew || 
        (this.firstName.length > 0 && this.lastName.length > 0);
    }
    
    // Note the function type literal used for the "completeCallback" parameter.
    // "repository" has no type. Therefore it is of type "Any".
    public savePerson(repository, completedCallback: (bool) => void) {
      var code = repository.saveViaRestService(this);
      completedCallback(code === 200);
    }
  }
  
  // Create derived classes using the "extends" keyword
  export class VipPerson extends Person {
    // Note that "VipPerson" does not define a constructor. It gets a
    // constructor with appropriate parameters from its base class
    // automatically.
    
    // Note how we override "toString" here. Use "super" to access 
    // the base class.
    public toString() {
      return super.toString() + " (VIP)";
    }
  }
  
  // Define a nested module inside of CrmModule
  export module Sales {
    export class Opportunity {
      public potentialRevenueEur: number;
      public contacts: IPerson[];      // Array type
      
      // Note that we use the "IPerson" interface here.
      public addContact(p: IPerson) {
        this.contacts.push(p);
      }
      
      // A static member...
      static convertToUsd(amountInEur: number): number {
        return amountInEur * 1.3;
      }
    }
  }
}

// Note how we instanciate the Person class here.
var p: CrmModule.Person;
p = new CrmModule.Person("Max", "Muster");

// Change the HTML DOM via TypeScript. Try to play around with this code
// in the TypeScript Playground and you will see that you have IntelliSense
// when working with the DOM. Accessing the DOM is type safe.
var button = document.createElement('button')
button.innerText = p.toString()
button.onclick = function() {
  alert("Hello" + p.firstName)
}
document.body.appendChild(button)

// Call a method and pass a callback function.
var r = { 
  saveViaRestService: function (p: CrmModule.Person) {
    alert("Saving " + p.toString());
    return 200;
  }
};
p.savePerson(r, function(success: string) { alert("Saved"); });

// Create an instance of the derived class.
var v: CrmModule.VipPerson;
v = new CrmModule.VipPerson("Tom", "Turbo");
// Note how we access the get accessor here.
if (!v.isValid) {
  alert("Person is invalid");
}
else {
  // Not that "toString" calls the overridden version from the derived class
  // VipPerson.
  alert(v.toString());
}

// Note how we import a module here and assign it the alias "S".
import S = CrmModule.Sales;
var s: S.Opportunity;
s = new S.Opportunity();
s.potentialRevenueEur = 1000;
// Note structural subtyping here. You can call "addContact" with 
// any object type compatible with IPerson.
s.addContact(v);
s.addContact({ firstName: "Rainer", lastName: "Stropek" });
s.addContact(<CrmModule.IPerson> { firstName: "Rainer", lastName: "Stropek" });
var val = S.Opportunity.convertToUsd(s.potentialRevenueEur);

Modules in TypeScript

module Crm {
	export class Customer {
		constructor(public custName: string) {
		}
	}
}

module Crm {
	export class Opportunity {
		constructor(public customer: Customer) {
		}
	}	
}

var classesInCrmModule = "";
for(var key in Crm)
{
	 classesInCrmModule += key + " ";
	 
}
document.body.innerText = classesInCrmModule;

Interfaces and Ambient Declarations

The second sample shows the power of Ambient Declarations in TypeScript:

jQuery.d.ts:

interface JQueryEventObject extends Event {
  preventDefault(): any;
}

interface JQuery {
  ready(handler: any): JQuery;
  click(handler: (eventObject: JQueryEventObject) => any): JQuery;
}

interface JQueryStatic {
  (element: Element): JQuery;
  (selector: string, context?: any): JQuery;
}

declare var $: JQueryStatic;

app.ts:

/// <reference path="jQuery.d.ts" />

$(document.body).ready(function(){
	alert("Loaded");
    $("a").click(function(event) {
        alert("As you can see, the link no longer took you to timecockpit.com");
        event.preventDefault();
   });
});

default.htm:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>jQuery from TypeScript</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="app.js"></script>
</head>
<body>
    <h1>jQuery from TypeScript</h1>
    <div id="content">
        <a href="http://www.timecockpit.com">Click me!</a>
    </div>
</body>
</html>
comments powered by Disqus

Rainer Stropek

Rainer Stropek

Co-founder, architect, developer

Bio

I am co-founder and CEO of the company software architects and have been serving this role since 2008. At software architects my team and I are developing the award-winning SaaS solution time cockpit. Previously, I founded and led IT consulting firms that worked in the area of developing software solutions based on the Microsoft technology stack.

In my work I focus on .NET development and software architecture. I have written some books and articles on C#, database development, Windows Azure, Windows 8 development, WPF, and Silverlight. Regularly I speak at conferences, do workshops and conduct trainings in Europe and the US. Since 2010 I have been MVP for Windows Azure.

I graduated the Higher Technical School Leonding (AT) for MIS with honors and hold a BSc (Hons) Computer Studies of the University of Derby (UK).

Contact

Twitter: @rstropek
Facebook
Google+
Xing
LinkedIn

Authors