Ionic 2: TypeScript vs ECMAScript 6
By Josh Morony
The title of this post, although it describes the intention, might be a little bit confusing. TypeScript and ECMAScript 6 (ES6) are not really two different things battling it out, TypeScript is just an extension of the standard ECMAScript 6 syntax.
If you’ve done any research into what TypeScript is you may have seen it referred to as a “typed superset of JavaScript”, which is a very succinct description but I think it suffers from the typical problem of making things sound more complicated than they are.
Depending on which stats or mathematics courses you took in school and how good your memory is, you may or may not know what a “superset” is. If we have a set of data (A), then a superset (B) of that data would contain everything that is in set A, as well as some more data:
So in the context of TypeScript, this means that it contains everything that JavaScript contains with a few other things added as well:
The description also mentions that it is a “typed” superset, which just means that it includes types. If you have used some other programming languages like Java or C++ then you would be familiar with types. A type basically specifies what a variable is, or what a function returns, but we will talk about that in a moment.
Standard ES6 is perhaps a little bit less confusing for beginners (although as you will see, dependency injection is actually a little harder with ES6), but since TypeScript is seeing such wide adoption a lot of the resources being created are for TypeScript, and even the official Angular and Ionic 2 documentation are currently written in TypeScript.
The differences between the two approaches aren’t huge, and it’s reasonably straightforward to convert between the two. If you’re familiar with TypeScript and come across some ES6 code you could quite easily convert it, and vice versa. But if you are a complete beginner and don’t understand why there are two different ways to use the same thing, you might end up trying to use TypeScript code in your ES6 project which won’t work.
So let’s talk about the difference between ECMAScript 6 and TypeScript in Ionic 2.
TypeScript and ECMAScript 6 in Ionic 2
The Ionic CLI supports generating both TypeScript and ES6 projects. Fortunately, the CLI handles all of the setup required to run both types of projects so there’s no heavy lifting required on the users end here. Currently if you start a project with the following command:
ionic start MyApp Blank --v2
then you will have a standard ES6 project generated with .js files. If you take a look at the app.js file it would look something like this:
import {App, Platform} from 'ionic-angular'; import {StatusBar} from 'ionic-native'; import {HomePage} from './pages/home/home'; @App({ template: '<ion-nav [root]="rootPage"></ion-nav>', config: {} }) export class MyApp { static get parameters() { return [[Platform]]; } constructor(platform) { this.rootPage = HomePage; platform.ready().then(() => { StatusBar.styleDefault(); }); } }
But if you include the
--ts flag when creating a project like this:
ionic start MyApp blank --v2 --ts
you will get a TypeScript project with .ts files. If you take a look at the app.ts file it would look something like this:
import {App, Platform} from 'ionic-angular'; import {StatusBar} from 'ionic-native'; import {HomePage} from './pages/home/home'; @App({ template: '<ion-nav [root]="rootPage"></ion-nav>', config: {} }) export class MyApp { rootPage: any = HomePage; constructor(platform: Platform) { platform.ready().then(() => { StatusBar.styleDefault(); }); } }
Pretty similar. The only real differences here are types:
rootPage: any = HomePage;
and dependency injection:
constructor(platform: Platform)
We’re going to talk through both of these concepts in a little bit more detail now.
Types
Types are pretty much the whole point of using TypeScript over ES6. Before ES6, which introduced things like classes, block scoping, and more, a huge benefit of using TypeScript was that it allowed you to use all of these features even with older versions of JavaScript. These features are supported natively now in ES6, but TypeScript still provides the added benefit of types which standard ES6 does not.
When declaring a variable in plain old ES6 you might just do something like this:
let myThing = "hello";
but with TypeScript you would do something like this:
let myThing: any = "hello";
The
any in the code above is a type, which is basically saying “this variable can be any type of data”. Let’s take a look at a couple more examples:
let http: Http = http; let myNumber: Number = 3; let myString: String = "hello";
Now we have given each variable some specific types. The data contained in
http must be of the Http type,
myNumber must be a number, and
myString must be a string. If we were to change
myNumber to the following:
`let myNumber: Number = “oops!“;
we would get the following error in the command line:
TypeScript error: Error TS2322: Type 'string' is not assignable to type 'Number'.
Because we are trying to assign a text string to a variable that is supposed to be for numbers.
Why would we want to do this? It might seem like types just make things more complicated, but it does have its benefits. By using types our program knows what type of data it is expecting, and if the types do not match then it will complain and let us know that there is a problem. This is basically a really simple way to add some basic error checking into the application. It also makes dependency injection much nicer which we will talk about a little later.
Dependency Injection
We can use the concept of types to greatly simplify dependency injection. If you take a look at the
constructor from our ES6 example it looks like this:
constructor(platform)
What we are trying to do is inject the
Platform service which is imported at the top of the file into the constructor, and we would like that available under the variable name
platform which we have specified in the constructor. For dependency injection to work then our app needs to know what this
platform variable is supposed to be a reference to the
Platform service.
So with ES6 we add this little weird bit of code above our constructor:
static get parameters() { return [[Platform]]; } constructor(platform){ }
What this does is say that we want the first parameter in our
constructor to be a reference to
Platform. If we wanted to inject multiple services then we would do something like this:
static get parameters() { return [[Platform], [Http]]; } constructor(platform, http){ }
Note that it is not necessary that the constructor parameters are lower case versions of the services being injected, you can name them whatever you want – it’s just the order that is important.
When doing dependency injection with TypeScript we can use types to specify the service that is being injected instead, like this:
constructor(platform: Platform)
Since we have specified that
platform has a type of
Platform our app knows what we want the
platform parameter to be.
Summary
Although TypeScript certainly has its benefits (not all of which I have mentioned here), in the end it’s not a huge deal which style you prefer. As you can probably tell from this post, the syntax differences aren’t huge and you should pretty easily be able to convert from one to the other.
The “battle” between standard ES6 and TypeScript is one of adoption, not features, and it seems that TypeScript is winning that battle. Unless you have a specific reason not to, then you should use TypeScript. You would be going against the grain not to and there’s no real benefit to using standard ES6.
I originally wrote Building Mobile Apps with Ionic 2 using ES6, as this is currently the default that the Ionic team uses. Since TypeScript is this extra thing, it makes sense that it would be easier for beginners to stick with the basics and those who want to use TypeScript can. Since TypeScript is being so widely used though, it’s actually making it harder for beginners to start on ES6. The Ionic team have stated that they will be moving to using TypeScript by default (so you will no longer need to include the
--ts flag when creating TypeScript projects, and will instead use a
--js flag to create an ES6 project).
In future blog posts I will be writing tutorials with TypeScript, and I will also be updating my eBook to use TypeScript as well (for those of you who already have it, this will likely be included in the next update of the book).