Typescript is the new kid on the block, a newly attempt to bring order to the javascript chaos. ES6 is around the corner and is a fantastic step forward for frontend development (classes!) but it will take years to be fully implemented in all major browsers. That’s when Typescript comes to the rescue. Typescript goal is to be a superset of ES6 that, in addition to all the new stuff that the standard is defining, will add a static type system. Typescript has also a transpiler that converts our Typescript code (i.e. ES6 + types) to ES5 or ES3 javascript code so we can use it in today browsers.
Having a type system means that our code is much more maintainable, less error prone, and that our IDEs will become more intelligent because of static analysis and code completion. Other attempts have been made in the past to overcome javascript deficiencies, being Coffescript the most well known, but those languages had a major flaw: you have to learn a completely new language. Typescript took another approach and didn’t reinvent the wheel, all javascript code is in fact typescript code, every new feature of typescript is optional. It means that the learning curve is very soft and that we can implement new features in our code incrementally. Way to go Microsoft!
Installing Typescript
First things first, we need to install typescript in our computers, so we use npm to install it globally.
$ npm install -g typescript
Although the package is called typescript, the command that executes the transpiler is called tsc . Because typescript is in constantly development we need to make sure of the version that we are using.
$ tsc --version
Currently I’m using typescript 1.4.1, the latest stable release. When I stated that typescript is a superset of ES6 i lied a little, because version 1.4 lacks some of the features present in ES6, however, typescript 1.5 will close that gap and will add more unique features like annotations.
Transpiling Code from Typescript to Javascript
Ok now that we have the typescript transpiler installed in our machines, is time to use it. Lets create our first typescript file and use some of the new features of ES6. We wil call the file “person.ts”. Don’t forget to use .ts extension.
class Person {
public firstName: string;
public lastName: string;
constructor (firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
}
We are using the new class syntax definition from ES6 using typescript so the next step is to use the transpiler to obtain javascript code.
$ tsc person.ts
The transpiler creates a new file called “person.js” with the javascript code.
var Person = (function () {
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
return Person;
})();
So now we have the same Person class implemented with the classical convoluted javascript code that we can use in our browsers or in node.
Changing Javascript Target
Let’s add a new property to our class, this time a private one that it’s only available through an accessor.
class Person {
public firstName: string;
public lastName: string;
private _fullName: string;
constructor (firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}
And use the transpiler again to obtain the javascript counterpart.
$ tsc person.ts
person.ts(11,6): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
An error? What just happened? It turns out that the proper way to define an accessor in javascript is using Object.defineProperty() that is only available in ES5 and onward, but as default, the transpiler tries to create ES3 code. To overcome this problem we have to tell the transpiler that it should target ES5 and not ES3.
$ tsc person.ts --target ES5
Now it works! The transpiler creates a new person.js file, overwriting the old one.
var Person = (function () {
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Object.defineProperty(Person.prototype, "fullName", {
get: function () {
return "" + this.firstName + " " + this.lastName;
},
enumerable: true,
configurable: true
});
return Person;
})();
It’s possible to instruct the transpiler to create ES6 code but it’s not really useful right now because ES6 does not have wide support among browsers and because there’s another fundamental problem: It doesn’t work.
Let’s try to use he same code and use the transpiler to create ES6 javascript code.
$ tsc person.ts --target ES6
And this is what we get in return:
var Person = (function () {
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Object.defineProperty(Person.prototype, "fullName", {
get: function () {
return `${this.firstName} ${this.lastName}`;
},
enumerable: true,
configurable: true
});
return Person;
})();
The exact same result that when using ES5 as target. That’s a very odd behavior considering that ES6 defines classes with constructor and getters so the typescript code shown before should be considered a valid ES6 javascript code. The transpiler should have only trimmed the type definitions and changed the file extension to “.js”. Maybe because ES6 is not formally ready, the typescript team is still working on the implementation of the transpiler for that version of javascript.
Looking at the help file for the tsc command we can see that the target “ES6” is marked as experimental.
$ tsc --help
Version 1.4.1.0
Syntax: tsc [options] [file ...]
Examples: tsc hello.ts
tsc --out file.js file.ts
tsc @args.txt
Options:
-d, --declaration Generates corresponding '.d.ts' file.
-h, --help Print this message.
--mapRoot LOCATION Specifies the location where debugger should locate map files instead of generated locations.
-m KIND, --module KIND Specify module code generation: 'commonjs' or 'amd'
--noEmitOnError Do not emit outputs if any type checking errors were reported.
--noImplicitAny Warn on expressions and declarations with an implied 'any' type.
--out FILE Concatenate and emit output to single file.
--outDir DIRECTORY Redirect output structure to the directory.
--preserveConstEnums Do not erase const enum declarations in generated code.
--removeComments Do not emit comments to output.
--sourceMap Generates corresponding '.map' file.
--sourceRoot LOCATION Specifies the location where debugger should locate TypeScript files instead of source locations.
--suppressImplicitAnyIndexErrors Suppress noImplicitAny errors for indexing objects lacking index signatures.
-t VERSION, --target VERSION Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)
-v, --version Print the compiler's version.
-w, --watch Watch input files.
@<file> Insert command line options and files from a file.
Watching Changes
It’s a little bit tedious to call the transpiler every time we make a change to person.ts so instead we can use a watcher to automate the process.
$ tsc person.ts --target ES5 --watch
Going a step further, if we define a folder called “ts” for all of our typescript files, and a folder called “js” for the transpiled code, we can setup the watcher like this:
$ tsc ts/*.ts --target ES5 --outDir js --watch
The –outDir flag tells the transpiler where tu put all the javascript files, in this case the “js” folder. Now, whenever we make a change to any file in the “ts” folder, the transpiler kicks in and creates all the associated javascript files and put them in the “js” folder.
In a next post we are going to explore how to integrate typescript into Sublime Text to obtain syntax highlighting and code completion (coming soon).
Pendiente de tus publicaciones.