TypeScript Tutorial
TypeScript Tutorial
JavaScript is pretty good as it is and you may wonder Do I really need to learn
TypeScript? Technically, you do not need to learn TypeScript to be a good developer,
most people do just fine without it. However, working with TypeScript definitely has its
benefits:
Due to the static typing, code written in TypeScript is more predictable, and is
generally easier to debug.
Makes it easier to organize the code base for very large and complicated apps
thanks to modules, namespaces and strong OOP support.
TypeScript has a compilation step to JavaScript that catches all kinds of errors
before they reach runtime and break something.
The upcoming Angular 2 framework is written in TypeScript and it's recommended
that developers use the language in their projects as well.
The last point is actually the most important to many people and is the main reason to
get them into TypeScript. Angular 2 is one of the hottest frameworks right now and
although developers can use regular JavaScript with it, a majority of the tutorials and
examples are written in TS. As Angular 2 expands its community, it's natural that more
and more people will be picking up TypeScript.
Installing TypeScript
You will need Node.js and Npm for this tutorial. Go here if you don't have them installed.
The easiest way to setup TypeScript is via npm. Using the command below we can
install the TypeScript package globally, making the TS compiler available in all of our
projects:
npm install -g typescript
Try opening a terminal anywhere and running tsc -v to see if it has been properly
installed.
tsc -v
Version 1.8.10
Compiling to JavaScript
TypeScript is written in .ts files (or .tsx for JSX), which can't be used directly in the
browser and need to be translated to vanilla .js first. This compilation process can be
done in a number of different ways:
In the terminal using the previously mentioned command line tool tsc.
Directly in Visual Studio or some of the other IDEs and text editors.
Using automated task runners such as gulp.
We found the first way to be easiest and most beginner friendly, so that's what we're
going to use in our lesson.
The following command takes a TypeScript file named main.ts and translates it into its
JavaScript version main.js. If main.js already exists it will be overwritten.
tsc main.ts
We can also compile multiple files at once by listing all of them or by applying wildcards:
# Compiles all .ts files in the current folder. Does NOT work recursively.
tsc *.ts
We can also use the --watch option to automatically compile a TypeScript file when
changes are made:
Static Typing
A very distinctive feature of TypeScript is the support of static typing. This means that
you can declare the types of variables, and the compiler will make sure that they aren't
assigned the wrong types of values. If type declarations are omitted, they will be
inferred automatically from your code.
Here is an example. Any variable, function argument or return value can have its type
defined on initialization:
speak(burger, calories);
Because TypeScript is compiled to JavaScript, and the latter has no idea what types
are, they are completely removed:
speak(burger, calories);
However, if we try to do something illegal, on compilation tsc will warn us that there is
an error in our code. For example:
Interfaces
Interfaces are used to type-check whether an object fits a certain structure. By defining
an interface we can name a specific combination of variables, making sure that they will
always go together. When translated to JavaScript, interfaces disappear - their only
purpose is to help in the development stage.
// Here we define our Food interface, its properties, and their types.
interface Food {
name: string;
calories: number;
}
// We tell our function to expect an object that fulfills the Food interface.
// This way we know that the properties we need will always be available.
function speak(food: Food): void{
console.log("Our " + food.name + " has " + food.calories + " calories.");
}
// We define an object that has all of the properties the Food interface
expects.
// Notice that types will be inferred automatically.
var ice_cream = {
name: "ice cream",
calories: 200
}
speak(ice_cream);
The order of the properties does NOT matter. We just need the required properties to
be present and to be the right type. If something is missing, has the wrong type, or is
named differently, the compiler will warn us.
interface Food {
name: string;
calories: number;
}
speak(ice_cream);
main.ts(16,7): error TS2345: Argument of type '{ nmae: string; calories:
number; }
is not assignable to parameter of type 'Food'.
Property 'name' is missing in type '{ nmae: string; calories: number; }'.
This is a beginners guide so we won't be going into more detail about interfaces.
However, there is a lot more to them than what we've mentioned here so we
recommend you check out the TypeScript docs - here.
Classes
When building large scale apps, the object oriented style of programming is preferred by
many developers, most notably in languages such as Java or C#. TypeScript offers a
class system that is very similar to the one in these languages, including inheritance,
abstract classes, interface implementations, setters/getters, and more.
It's also fair to mention that since the most recent JavaScript update (ECMAScript
2015), classes are native to vanilla JS and can be used without TypeScript. The two
implementation are very similar but have their differences, TypeScript being a bit more
strict.
class Menu {
// Our properties:
// By default they are public, but can also be private or protected.
items: Array<string>; // The items in the menu, an array of strings.
pages: number; // How many pages will the menu be, a number.
// A straightforward constructor.
constructor(item_list: Array<string>, total_pages: number) {
// The this keyword is mandatory.
this.items = item_list;
this.pages = total_pages;
}
// Methods
list(): void {
console.log("Our menu for today:");
for(var i=0; i<this.items.length; i++) {
console.log(this.items[i]);
}
}
}
// Just like the properties, methods are inherited from the parent.
// However, we want to override the list() function so we redefine it.
list(): void{
console.log("Our special menu for children:");
for(var i=0; i<this.items.length; i++) {
console.log(this.items[i]);
}
}
}
// This time the log message will begin with the special introduction.
menu_for_children.list();
For a more in-depth look at classes in TS you can read the documentation - here.
Generics
Generics are templates that allow the same function to accept arguments of various
different types. Creating reusable components using generics is better than using
the any data type, as generics preserve the types of the variables that go in and out of
them.
A quick example would be a script that receives an argument and returns an array
containing that same argument.
// The <T> after the function name symbolizes that it's a generic function.
// When we call the function, every instance of T will be replaced with the
actual provided type.
Modules
Another important concept when working on large apps is modularity. Having your code
split into many small reusable components helps your project stay organized and
understandable, compared to having a single 10000-line file for everything.
TypeScript introduces a syntax for exporting and importing modules, but cannot handle
the actual wiring between files. To enable external modules TS relies on third-party
libraries: require.js for browser apps and CommonJS for Node.js. Let's take a look at a
simple example of TypeScript modules with require.js:
We will have two files. One exports a function, the other imports and calls it.
exporter.ts
var sayHi = function(): void {
console.log("Hello!");
}
export = sayHi;
importer.ts
import sayHi = require('./exporter');
sayHi();
Now we need to download require.js and include it in a script tag - see how here. The
last step is to compile our two .ts files. An extra parameter needs to be added to tell
TypeScript that we are building modules for require.js (also referred to as AMD), as
opposed to CommonJS ones.
tsc --module amd *.ts
Modules are quite complex and are out of the scope of this tutorial. If you want to
continue reading about them head out to the TS docs - here.
Non-nullable types flag which prevents some variables from having their value set
to null or undefined.
New improved system for getting declaration files directly with an npm install.
Control flow type analysis that catches errors previously missed by the compiler.
Some innovations in the module export/import syntax.
Another long-awaited feature is the ability to control the flow of asynchronous functions
in an async/awaitblock. This should be available in a future 2.1 update.
Further Reading
The amount of information in the official docs can be a bit overwhelming at first, but the
benefits of going through it will be huge. Our tutorial is to be used as an introduction, so
we haven't covered all of the chapters from the TypeScript documentation. Here are
some of the more useful concepts that we've skipped:
Namespaces - here.
Enums - here.
Advanced Types and Type Guards - here.
Writing JSX in TypeScript - here.
Conclusion
We hope you enjoyed this tutorial!
Do you have any thoughts on TypeScript and would you consider using it in your
projects? Feel free to leave a comment below!