When building an Ionic 2 application you have a choice between using regular ECMAScript 6 syntax, or TypeScript. If you’re unfamiliar with what these are I’d recommend reading Intro to ECMAScript 6 and Angular 2 for Ionic Developers and for a little more context on what some of the issues are around the two options I’d recommend reading Ionic 2: TypeScript vs ECMAScript 6.
To create a regular ES6 project you would start an Ionic 2 project with the following command:
ionic start MyApp --v2
or to create a TypeScript project you would run:
ionic start MyApp --v2 --ts
If you’ve been following my tutorials then you would know that most of them have used the ES6 syntax. This is because it is the default option and, keeping beginners in mind, it made sense that it would be easier to focus on the basics before adding “extra” things like TypeScript.
The opposite has been the case though, using the standard ES6 syntax has actually made things more complicated for beginners. This is mostly because of two reasons: dependency injection is super weird with ES6, and most of the resources being developed use TypeScript. A lot of beginners may not know about TypeScript and when they try to use TypeScript syntax from tutorials in their ES6 projects it inevitably won’t work.
There’s a strong move towards TypeScript now. The Ionic 2 and Angular 2 documentation uses TypeScript, most developers who have used TypeScript prefer it, and it will soon become the default option for Ionic 2 projects (meaning you would instead include a --js
flag to create an ES6 project, instead of a --ts
flag to create a TypeScript one).
In this tutorial I am going to show you how to take some ES6 code and convert it to TypeScript (a task I just finished on all 500 pages of Building Mobile Apps with Ionic 2). As you will see, the differences between the two are minor. After reading this you should be able to easily recognise the difference between the two approaches, and convert between them.
ECMAScript 6
Let’s start with a block of ES6 code. This is a snippet from one of the example applications in the book, and it covers just about all the syntax you will need to know.
import { Page, NavController, Alert } from 'ionic-angular';
import { ChecklistPage } from '../checklist/checklist';
import { Data } from '../../providers/data/data';
@Page({
templateUrl: 'build/pages/home/home.html',
})
export class HomePage {
static get parameters() {
return [[NavController], [Data]];
}
constructor(nav, dataService) {
this.dataService = dataService;
this.nav = nav;
this.someString = 'cool!';
this.someNumber = 42;
}
addChecklist() {
let prompt = Alert.create({
title: 'New Checklist',
body: 'Enter the name of your new checklist below:',
inputs: [
{
name: 'name',
},
],
buttons: [
{
text: 'Cancel',
},
],
});
this.nav.present(prompt);
}
save() {
this.dataService.save(this.checklists);
}
}
We’re importing some stuff, injecting a couple services and setting up member variables, and there’s two functions. One function creates an Alert and the other makes a call to the data service.
TypeScript (bare bones)
Now let’s port that code over to TypeScript. First we are going to take a “bare bones” approach, where we only do what is 100% necessary to get it working. In fact, you don’t need to do anything to get it working, you can literally use the exact same code. Since TypeScript builds on top of normal Javascript, “normal” Javascript still works fine, which means we don’t even need to change the static get parameters
method of dependency injection. You might get some complaints from the TypeScript compiler, but it will still work.
What you will usually see though will look something like this:
import { Page, NavController, Alert } from 'ionic-angular';
import { ChecklistPage } from '../checklist/checklist';
import { Data } from '../../providers/data/data';
@Page({
templateUrl: 'build/pages/home/home.html',
})
export class HomePage {
constructor(nav: NavController, dataService: Data) {
this.dataService = dataService;
this.nav = nav;
this.someString = 'cool!';
this.someNumber = 42;
}
addChecklist() {
let prompt = Alert.create({
title: 'New Checklist',
body: 'Enter the name of your new checklist below:',
inputs: [
{
name: 'name',
},
],
buttons: [
{
text: 'Cancel',
},
],
});
this.nav.present(prompt);
}
save() {
this.dataService.save(this.checklists);
}
}
Now dependency injection works just by giving the parameters in the constructor
a type of whatever service is being injected. A type is assigned by using a colon :
to the right of the variable, and then whatever the type is. So in this case we have a parameter nav
with a type of NavController
and a parameter dataService
with a type of Data
, so now our constructor knows what services we are trying to inject.
Everything else is still the same.
TypeScript (expanded)
Now let’s take a look at a “proper” TypeScript example:
import {Page, NavController, Alert} from 'ionic-angular';
import {ChecklistPage} from '../checklist/checklist';
import {Data} from '../../providers/data/data';
@Page({
templateUrl: 'build/pages/home/home.html'
})
export class HomePage {
someString: string = "cool!";
someNumber: number = 42;
constructor(public nav: NavController, public dataService: Data) {
}
addChecklist(): void {
let prompt: Alert = Alert.create({
title: 'New Checklist',
body: 'Enter the name of your new checklist below:',
inputs: [
{
name: 'name'
}
],
buttons: [
{
text: 'Cancel'
}
]
});
this.nav.present(prompt);
}
save(): void {
this.dataService.save(this.checklists);
}
}
Now things are looking a little different. We’ve added the public
keyword (you can also use private
) in the constructor to automatically create member variables for nav
and dataService
. This removes the need to do this.nav = nav;
. We have also moved our other member variables outside of the constructor, which again automatically creates member variables for them.
We’ve assigned a bunch of types to things. We’ve given the string
and number
types to the member variables, and we’ve even given a type of Alert
to the prompt inside of the addChecklist
function. We are also giving types to the functions themselves, since they both don’t return any data we give them a type of void
. If they were to return some data then we would just give them a type of whatever data they return.
Common types for variables include:
string
(a string)number
(a number)boolean
(true or false)any
(like a wildcard, can be anything)
and there are also more complex types available like:
string[]
(an array of strings)Array<string>
(also an array of strings)Promise<any>
(a promise that can return any type)Alert
(if you’re using an Ionic 2 alert, then you can use an Alert type!)
You can include as many or as few types as you want. You don’t need to give a type to every single variable and function. Maybe you want to just add types to your member variables. The more types you use the more checks the compiler is able to perform on your code, but you can do whatever you’re comfortable with.
Summary
I think the scariest looking thing about TypeScript is the types, but as you can see from this post they are completely optional (I would recommend using them for dependency injection though since it’s a lot easier) and not all that hard once you get your head around it. So if you are using ES6 currently, I would recommend switching to TypeScript and just doing whatever you’re comfortable with. There are benefits to adding types to your code, but it is absolutely not a requirement.
So let’s quickly summarise the key differences between ES6 and TypeScript.
- TypeScript files have a
.ts
extension instead of.js
- TypeScript allows (but does not require) the use of types for both variables and functions
- Types can be used for dependency injection in TypeScript
- TypeScript provides compile time warnings for potential issues
Hopefully this tutorial has helped clear up the difference between the two approaches.