Getting Started With TypeScript
Written by Mike James   
Wednesday, 03 October 2012
Article Index
Getting Started With TypeScript
The Type System
Interfaces

The Module

The TypeScript module is nothing new to the JavaScript programmer. The simplest module is something like:

module MyModule{
export var myVariable;

}

You can define variables, objects, classes, interfaces and functions within the module. Everything that you define is created in JavaScript within an encapsulating object with the same name as the module. So to access myVariable you would have to write

MyModule.myVariable

Anything that you don't export is private to the module and cannot be accessed by the external world. 

The module is implemented in JavaScript as an anonymous function that is executed at once to create an object that contains all of the modules members. Modules can extend existing modules of the same name.  Modules can be internal, i.e. defined in the same file, or external in another file of the same name. The import MyModule instruction loads MyModule.js.

There is a lot more to say about the fine detail of modules but essentially what we have is the CommonJS, AMD or the namespace idiom in JavaScript made slightly easier to use.

Class

The TypeScript class construct is much what you would expect. You can define a class:

class MyClass{
}

and the body of the class can contain functions, variables and objects. A constructor of the same name as the class is declared using:

constructor(parameters)

A class can inherit from another class, or as we shall see later from an interface using the extends or  implements keyword. To call the base class constructor you use the super keyword.

Members of the class can be declared as static and these belong to the constructor function and so appear to belong to the class rather than the instance. You have to use the this keyword when working with class or instance members. 

You can override inherited methods and properties by simply redefining them.

Instance members can be declared as public or private with the default being public. This sounds a wonderful step forward because JavaScript objects can't have private members but as it turns out neither can TypeScript objects. The private declaration is taken notice off only at compile time and if you try to access a private member then you will generate a compile time error. There are ways of dynamically accessing private members at runtime without generating an error.

Classes are implemented in JavaScript by the creation of a standard constructor function of the same name. Inheritance is implemented by chaining prototype objects.

Once again most of this is available in standard JavaScript if you use the appropriate idiom. TypeScript simply provides a perhaps easier and clearer way of writing it.

The Type System

Of course it is the type system that makes TypeScript either worth using or not. By comparison the rest is fairly simple stuff. Imposing a type system on a superset of JavaScript is no simple matter because to contain JavaScript objects can dynamically change their type.

In JavaScript there is no concept of a fixed type - objects simply acquire and lose the methods and properties they need. In addition to this difficulty functions are first class objects, i.e. they are object you happen to be able to call and evaluate, and this makes the concept of type even more sophisticated.

What do JavaScript programmers do to cope with this situation?


They resort to duck typing. Forget the ideas of a type hierarchy based on inheritance. All that matters is that an object has the properties and methods you want to use.

Interestingly this is the approach that TypeScript takes, but it is heavily disguised as static hierarchical typing.

In TypeScript a type is simply a specification for a set of methods and properties an object has. It can be taken as a statement of what it is safe to use and what the object is expected to support.

The type system starts with any, which you can consider to be the top of the type hierarchy, but it is best thought of as a statement that nothing is known about the type. In other words, you can use any method or property in any way that you like and no compiler errors will be generated. Clearly if we are going to rely on type checking we need to use any as little as possible.

The primitive types are number, boolean, string, null and undefined and they directly correspond to the JavaScript primitive types.

To allow functions to act as procedures i.e. to not return a result, we also have the special type void which means the absence of a value.

Type Inference

Whenever possible the system will infer a type for a variable. For example,

var i=1;

allows the system to infer that i is of type Number. After this assigning say a string generates a compile time error.

Type inference is impressive but it can be a problem.
Consider the following:

 

  if (false) {
        var i = 2;
    } else {
        var i = "hello";
    }

 

This is perfectly valid JavaScript and the type of i is clearly String. However in TypeScript i is typed as Number and the else clause generates a runtime error.

Perhaps the message is that you shouldn't write code like this, but you also need to be aware that type inference is lexical and not semantic.

You can explicitly type a variable using a type annotation. For example

var i:number=1;

sets i to be of type number and initializes it to one.

Clearly using explicit type annotation is a better idea than relying on type inference.

You can also form arrays of types using type[ ] - for example number[ ] is a numeric array.

 

Function Signatures

 

Functions are just objects you can call but in TypeScript you can specify the functions signature - the types of the parameters and return value. Notice that the return value is included in the signature - this is unusual.

Functions can also have required and optional parameters, marked by a trailing ? within the signature. You can also include a rest parameter which accepts any additional parameters - it has to be of type any[]

For example:

function myFunction(total:number, name:string):string;

defines a function with a signature number,string return string.  The function

function myFunction() :void;

accepts no parameters and returns no result.

When you call a function the parameter types have to match the signature.

Notice that if you don't specify a signature then one is inferred and type checking is performed using it.

You can also use function overloading i.e. same function with different signatures. In this case you can call the function without error if the call matches any of the signatures you specify.

For example:

 

function myFunction(x:number) :void;
function myFunction(x:string) :void;

This sounds exciting and useful but you have to implement the overloaded function in the original JavaScript style i.e. you have to work out what the types actually are in the call:

function myFunction(x:number) :void;
function myFunction(x:string) :void;
function myFunction(x: any): void {
    if (typeof x == "string") {
     do something with string
    } else {
    do somethign with number
    }
};

 

The type of the function doesn't include the actual implementation using any.



Last Updated ( Wednesday, 24 October 2012 )
 
 

   
RSS feed of all content
I Programmer - full contents
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.