How to get started with TypeScript

TypeScript is one of a group of languages that use the JavaScript runtime as execution environment: .ts files containing TypeScript code are compiled into normal JavaScript, which can then be run by the browser.

Jeremy Ashkenas first made this concept popular with his CoffeeScript language, but sadly, its relatively terse syntax was difficult to learn for developers acquainted with C# or Visual Basic.

As Microsoft expanded into Web 2.0 technologies, it chose to take inspiration from Jeremy Ashkenas. Due to the capabilities of Visual Studio, developers can simply hack away while profiting from the various language extensions.

TypeScript is not limited to static typing: it also comes with a variety of advanced features that allow you to simulate object-oriented programming paradigms on the web. This short guide will take you through some of its key features. If the language appeals to you, more information can be learned on the fly.

01. Install Visual Studio

Visual Studio 2017 comes with a new installer; the required features are split into payloads to make deployment easier

Even though TypeScript can also be used on Linux or macOS, we will stick to Microsoft’s official IDE. Download the free community edition of Visual Studio 2017 from Microsoft, here, and make sure to mark the ASP.NET payload during deployment.

02. Add the SDK

Due to the fast release cadence of TypeScript, Visual Studio needs to be expanded with an SDK module, which can be downloaded from the Microsoft site here. Simply run the installer as if it were a standard Windows application.

03. Download TypeScript, for real

It wouldn't be Microsoft if there weren’t some extra hassle involved: while the SDK upgrades your Visual Studio installation, the actual TSC compiler is not added to your command line. This problem is best solved by using Node.js’s npm package manager on the command line.

PS C:\Users\tamha\Downloads> npm install -g typescript

C:\Users\tamha\AppData\Roaming\npm\tsc -> C:\Users\tamha\AppData\Roaming\npm\node_modules\typescript\bin\tsc

C:\Users\tamha\AppData\Roaming\npm\tsserver -> C:\Users\tamha\AppData\Roaming\npm\node_modules\typescript\bin\tsserver

C:\Users\tamha\AppData\Roaming\npm

`--  typescript@2.4.2

04. Break out of the project

Visual Studio expects to work in a solution-centric process: while interesting, this is less than ideal for our needs. Instead, create a file called worker.ts and place it in a convenient place in your file system. Open it by dragging it into Visual Studio, and drop it inside the toolbar on the top. Next, modify its contents to include the following code:

function sayOi() {
  alert("Oi!");
}
sayOi();

05. Create an entry point

As mentioned in the introduction, a .ts file can not do much on its own. Due to that, proceed to creating a file called index.html, which must be located in the same folder. Next, add the skeleton code shown accompanying this step. It loads the compiler’s output, and runs it as if it were any other bit of JavaScript.

<html>
  <head>
  <script src="worker.js"></script>
  </head>
  <body></body>
</html>

06. Compile and run

The next step involves manual recompilation of the .ts file. Open PowerShell, and enter the tsc command followed by the name of the input file. By default, the output file will share the base filename, but will have an extension of .js instead of .ts. Finally, open the index.html file in a browser of choice to prove the appearance of the message box.

PS C:\Users\tamha\Downloads> tsc .\worker.ts

07. Get typed

Use this reference table to find basic static types

So far, TypeScript has done little more than act as a more complex JavaScript environment. The next step involves activating the support for static typing: it enables the compiler to perform static analysis of parameters, keeping out invalid values. For this, a set of types is needed – basic types are listed in the table above, while classes will be discussed later.

08. Try it out

In normal JavaScript, this error would be found only when the line in question gets invoked

TypeScript variable type assignments take place via ‘a :’ placed after the variable name. Let us modify our Oi function to take a number, and let us pass in a string instead. Finally, invoke the TSC compiler once again to feast your eyes on the error message shown in the screenshot above – Visual Studio, incidentally, will also highlight the line in question.

function sayOi(whatToSay: number) {
  alert(whatToSay);
}
sayOi("Hello");

09. Avoid the prototype

JavaScript implements object-orientation via prototyping: a style of code which is uncommon in the .NET and C/C++ worlds. TypeScript solves this problem by allowing the creation of classes – a process shown in the snippet accompanying this step.

class Imagine {
  public myResult: number;
  public myA: number;
  public myB: number;
  constructor(_a: number, _b: number)
  {
  this.myResult = _a + _b;
  this.myA = _a;
  }
}

10. Appreciate the public

The holding values created by setting the public attribute get populated automatically

Normally, the public attribute is used to declare that an element of a program is to be accessible from the outside. When used as a constructor parameter, it instead instructs the TypeScript compiler to create local fields with the same names.

class Imagine {
  public myResult: number;
  //public myA: number;
  constructor(public myA: number, public  _b: number)
  {
  this.myResult = myA + _b;
  this.myA = myA;
  }
}

11. Method and instance

Let us expand our example class by providing it with a method which accesses the values stored in myResult and myA, and outputs them on the screen. Finally, the new parameter is used to create an instance of the class – it is used for invoking the method.

class Imagine {
  public myResult: number;
  . . .
  public saySomething(): void {
  alert(this.myResult);
  }
}
let myImagine: Imagine = new Imagine(2, 2);
myImagine.saySomething();

12. Use its magical features

TypeScript’s language design is intended to save developers as much effort as possible. One nice feature is the auto-population of parameters created using the shortcut shown.

class Imagine {
  public myResult: number;
  constructor(public myA: number, public  myB: number)
  {
  this.myResult = myA + myB;
  }
  public saySomething(): void {
  alert(this.myA + “ “ + this.myB);
  }
}

13. Perform inheritance

Our small example program proves that TypeScript satisfies the core tenets of object inheritance

One of the core tenets of object-oriented programming involves basing classes on top of one another. Derived classes can then override the contents of their base class, leading to flexibly adjustable class hierarchies.

class Future extends Imagine
{
  public saySomething(): void {
  console.log(this.myA);
  }
}

14. Analyse the overwrite

The code snippet from above extended the Imagine class with a sub-element called Future. Future differs from Imagine in that its saySomething method, being more evolved, emits a message into the command line of the browser.

let myImagine: Imagine = new Future(2, 2);
myImagine.saySomething();
let myFuture: Future = new Future(9, 9);
myFuture.saySomething();

15. Analyse the overwrite, redux

With that, the actual code can be tested. When run, the browser console will contain two invocations of Future – the advanced class keeps its properties even when invoked as an Imagine object.

16. Restricted access

Exposing member variables with the public modifier is unpopular: it, after all, takes away most control of what users do with the variable's contents. TypeScript accessors allow you to work around this problem in a fashion similar to traditional OOP. Be aware that read-only members are also supported, but that the use of this feature requires the activation of ECMAScript5 support.

public _myCache: string;
  get fullCache(): string {
  return this._myCache;
  }
  set fullCache(newX: string) {
  if (newX == "hello") {
  this._myCache = newX;
  }
  else {
  console.log("Wrong data!");
  }
  }

17. Make it abstract

The ability to create complex inheritance hierarchies will motivate developers to try their luck at abstract classes. TypeScript also has you covered in that regard – the example accompanying this step creates a class with an abstract and a real member. Trying to instantiate the abstract class directly leads to a compiler error.

abstract class Imagine {
  public myResult: number;
  abstract sayName(): void;
  constructor(public myA: number, public  myB: number) {
  this.myResult = myA + myB;
  }
  public saySomething(): void {
  alert(this.myA + " " + this.myB);
  }
}
class Future extends Imagine {
  . . .
  public sayName() {
  console.log("Hello");
  }
}

18. Make an interface

As object structures become more complex, developers often find themselves facing situations where one class implements multiple bits of logic. In that case, an interface makes for a nice workaround – the example shows what to expect.

interface DataInterface {
  field: number;
  workerMethod(): void;
}

19. Implement it

As in the case of the class above, an interface does us no good if we cannot use it. Fortunately, implementing it is not particularly difficult: be aware that interface authors can, furthermore, declare parts of their creation to be optional.

class Worker implements DataInterface {
  field: number;
  workerMethod(): void {
  throw new Error("Method not implemented.");
  }
  }

20. Use a generic class

The TypeScript compiler enforces strict variable validity checking. When working on a storage class, generics allow you to let the end user determine the type to be handled. Furthermore, TypeScript also allows other generic elements such as functions, as is shown in the (tautological) snippet taken from the documentation.

//Generic function
function identity(arg: number): number {
  return arg;
}
//Generic class
class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T; }

21. A question of enumeration

State machines and similar elements benefit greatly from having a way to restrict a variable to storing a few well-defined states. This can be accomplished using the Enum data type:

enum ParserState {
  Idle = 1,
  Read0,
  Read1
}
class Imagine {
  public myState: ParserState;
  constructor(public myA: number, public  myB: number)
  {
this.myState = ParserState.Idle;

22. Learn more

Covering a language as complex as TypeScript in a single article is almost impossible. Look at the TypeScript site's examples to find out more about language bindings.

This article was originally published in issue 266 Web Designer, the creative web design magazine – offering expert tutorials, cutting-edge trends and free resources. Buy issue 266 here or subscribe to Web Designer here.

Special Christmas offer: Save up to 49% on a subscription to Web Designer for you or a friend for Christmas. It's a limited offer, so move quickly...

Related articles: