Learning Typescript and Building a Google Map with It
Typescript is a 2-year old powerhouse language, and is ordained as the official language for Angular js 2.0. Shall we learn some Typescript?
This UI development world is crazy, in good and bad ways. The good way, you can roll out from your tongue a stream of buzz words: ES 5, ES 6, jQuery, Angular 1, Angular 2, React js, Express js, Node js ...; the bad way, you (may) have no idea what you are talking about, not all of them.
Here is one more: a two year old power house: Typescript.
Search Typescript. Everyone recites the following as if it were part of the Ten Commandments:
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
What does that mean?
You check out some sample code; pretty much everyone honors the time-resisting grand-standing tradition: Hello. Hello world, hello you, hello John Doe!
It does not help much. What am I going to do after the hello?
Well, the following is my little journey of learning Typescript that goes a bit beyond the Hello. Hopefully, by sharing my pain and joy, I will spare you (some) of the pain and heighten the joy, and produce a Typescripted Google map like the following:
Or check out the following URL to see the map in action:
A Little Background
Surprise! Typescript is a Microsoft baby. Typescript was first released in 2012, after two years of internal development. It is created by Anders Hejlsberg, a Danish software engineer whose speciality is producing superb and massively popular languages (C#, Delphi).
Typescript has found a euphoric community, has had an ever growing list of support in IDES and text editors (Eclipse, Visual Studio 2013 update 2 and above, Sublime text, VIM, Emacs). Typescript has accumulated a powerful list of “friends”.
The most important of them (to me) is Angular 2 at Google. As a matter of fact, Angular 2 abandoned their own attempt of developing their superset language AtScript and now fully embraces Typescript.
Well, if Google follows suite, who would not?
Type Features / Where JavaScript Falls Short …
Types
Love it or hate it, JavaScript entrenched developers take for granted the chameleon nature of JavaScript data types. If you do not know 1+’1’ =’11’, 0-'1' = -1
or the sort, then your shine as a JavaScript developer will dim a bit :).
However, for server-side language expert, this is nothing but pure evil. Typescript gently agrees. They keep most of the basic JavaScript types, plus a Enum
and Void
. Undefined
is gone. They also throw in Any
, where you keep anything else for your convenience (at your own risk).
There are the following basic types in Typescript:
Boolean
(you typical yes and no, true and false):var youarecool:Boolean =true
Number
(no distinction betweenfloat
,int
,double
…)var salary: number = 10000000;
String
(this is where you sayHello World
)var helloWorld="Hello World!"
Array
(your bucket of value collection)var thingstodo:string[]={‘work’,’play’,’eat’, ‘sleep’};
Enum
(strict from C#, isn’t it?)enum weekdays {monday, tuesday};
Any
(Anything goes, proceed with caution)Anything else can be lumped under
any
. JavaScript developers are super comfortable withAny
. This is also where the vast objects go.//the following code is mostly from http://www.typescriptlang.org/Handbook#basic-types-any var notSure: any = 4; notSure=’not sure’; notSure=true; var list: any[]=[1, true, ‘whatever’]; list[1]=100.
Void
(For functions that do not need to return anything)function setName(): void{ console.log(‘I am not returning anything”) }
Not Everything Must be Definitely Typed
Though Typescript generally declares variables with their types, it is not strictly required. You can certainly slack your old’n’merry way:
var test;
test = 'whatever';
test = 1;
test = { a: 'whatever', b: 1 };
Though you cannot do this sort of crazy math anymore:
1-'1'
Typescript will throw an error as such:
The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.
Interfaces, Classes and Modules
Much of the pain/complaints in JavaScript derive from these 2 related deficiencies (from OO stand point of view):
- Lack of Object oriented class-based approaches, where the four OO pillars, encapsulations, inheritance, abstraction and polymorphism, are torturous (to some) to implement in JavaScript;
- Lack of code organization that is a must for any large scale application.
The proliferation of various JavaScript frameworks and the new ES 6 standard are all tried to remedy this, by introducing modules, namespaces, MVC architectures, etc.
Typescript’s solutions are interfaces, classes, and modules.
Interface is for abstraction, provides definition and structure of your classes, types and libraries.
For example:
interface IPerson {
name: string;
location: string;
age: number;
}
Classes provide, well, classes! Also inheritance, private
/public
modifiers, accessors, static
properties and more. Oh, that takes a whole book to write about classes. Plus, any C# devs will just say: oh shut up. So I just borrow the following code from typescript website.
class Animal {
private name:string;
constructor(theName: string) { this.name = theName; }
move(meters: number) {
alert(this.name + " moved " + meters + "m.");
}
}
Modules is Typescript's answer for namespacing, where you group your classes, interfaces, variables, functions into logic units.
My Grunts about Typescript
As a JavaScript developer, my learning of Typescript is not all rosy, eye-opening and filled with wonders, the sort that Alibaba stumbled into a treasures’ den with some magical words: Open Sesame.
No. There are things I am not really a big fan or have to get used to.
- I have to compile for every small bit of code change. I sometimes circumvent this step by directly changing / testing my Javascript then applying the change backwards. Not the best approach right?
- Typescript is a superset of JavaScript, it is not a super-rich heaven full of goodies. It provides structure and typed insight. However, without the rich content/repertoire that is the vast existing JavaScript libraries and components, Typescript would be completely crippled.
Definitelytyped
has a large repository of type definitions of various libraries. However: a) it is not nearly enough; b) not all typed definitions are created equal. It will need an army of slaves to type define a lot more libraries.Though you can always fool around by using the Typescript magical
Any
keyword as the following (see the stackoverflow post here).declare var SomeAwesomeLibrary: any; var beAwesome = new SomeAwesomeLibrary.DoSomeThing(); beAwesome.whatEver();
- Typescript aims to fix the issues with JavaScript, however, it also tries to appease the “real” JavaScript Ninjas, who likes JavaScript’ flexibilities and dynamic nature. As a result, Typescript in many ways tries to say ok to both OO class-based and JavaScript prototypical practice. I feel this could be a double edged sword and it may end up causing more confusion and indecisions.
- Official documentation is also lacking, many, many times StackOverflow is my only hope. My experience with using TypeScript with Sublime Text is not all smooth.
Let’s Roll Our Google Maps, Shall We?
Ok, now we have done our 5-minute long elevator speech; let’s roll our Google Maps, shall we?
First, follow instructions to get your Typescript by following the instruction here;
Second: take the necessary steps to bring in Typescript support to the IDE or editor of your chosen.
Now, grab the definition files (.d.ts) for the libraries we will need for this mapping project from DefinitelyTyped:
- Google map
- Google Map Marker cluster Plus (for grouping multiple markers for the same location)
Additionally, I use express js and node to serve my HTML files, so you may want to grab those as well. Or you can host your HTML in any other ways you prefer.
Some Typescript Code Now
Reference googlemap.d.ts and markerclustererplus file (make sure you set the path correctly):
/// <reference path="./typings/googlemaps/google.maps.d.ts" />
/// <reference path="./typings/markerclustererplus/markerclustererplus.d.ts" />
Create a module
, call it Mapping
:
module Mapping {
}
Inside the module
, add an interface of our map interest: IDeveloper
:
interface IDeveloper {
name: string;
location: string;
country: string;
latitude: number;
longitude: number;
icontype: string;
}
Create a class called GoogleMap
that plugs in the few strands of logic.
For my map, the constructor takes three parameters:
mapDiv
– the dom element that will host the mapdata
– map datatype
– type of maps
Inside of the constructor, I have some default map options set up.
Full constructor code is as follows:
constructor(mapDiv: Element, data: any[], type:string) {
var devs: Array<IDeveloper> = data;
var lats = [], longs=[];
var center: number[];
devs.map((value)=> {
lats.push(value.latitude);
longs.push(value.longitude);
});
center = this.getLatLngCenter(lats, longs);
this.options={
center: { lat: center[0], lng: center[1] },
scrollwheel: false,
zoom: 2
};
this.map = new google.maps.Map(mapDiv, this.options);
switch(type) {
case "heat":
this.map.setMapTypeId(google.maps.MapTypeId.SATELLITE);
this.addHeatMapLayer(data, this.map);
break;
default:
this.makeMakers(data, this.map);
break;
}
}
Other than the constructor, there are a few private
helper methods to set up the heat map layer, create clustered map markers, and methods to calculate the center point of the map.
For example, the heatMap
layer code is as follows:
addHeatMapLayer(data, map){
var points: google.maps.LatLng[] = [];
var devs: Array<IDeveloper> = data;
devs.map((value)=> {
points.push(new google.maps.LatLng(value.latitude, value.longitude));
});
var heatmap = new google.maps.visualization.HeatmapLayer({
data: points,
map: map
});
}
Please check out the full code at Github. The code is straightforward. There is also a spiderified map where map markers will fan out on click, which I build in plain JavaScript, since the library OverlappingMarkerSpiderfier does not have Typescript definition file.
Typescript Destructuring
Destructuring is one nice addition to ES6. Typescript supports it as well. My colleague is a particular fan of it. He points out to me that for the mapping part of the above code, it can be destructured as the following:
//BEFORE
devs.map((value)=> {
points.push(new google.maps.LatLng(value.latitude, value.longitude));
});
//AFTER
devs.map(({ latitude, longitude }) => {
points.push(new google.maps.LatLng(latitude, longitude));
});
After we have done our Typescript code, we can now compile it by using the command:
tsc mapping.ts
(tsc
is the Typescript compiler written in Typescript that compiles your Typescript file into JavaScript code. There are various options you can use with tsc
.)
With that, assuming the code compiles successfully, you should find a mapping.js in the same folder. Now we can work on our HTML code, include the js / css files as usual. Please do not forget to include all of the library JS files.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript">
</script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=visualization"></script>
<script type="text/javascript" src="libs/markerclusterer.min.js"></script>
<script type="text/javascript" src="mapping.js"></script>
<script type="text/javascript">
$(function(){
$.get("data/devs.json", function(data, status){
var mapCanvasCount = document.getElementById("mapDev");
var googleMap = new Mapping.GoogleMap(mapCanvasCount, data, 'count');
});
});
</script>
Disclaimer (Again) and Parting Words
As you can see, I am not an expert that has been soaking in this Typescript sunshine for a long time. I struggled, I searched, I stole code whenever appropriate; I endured the typical frustration of learning a new language, silently swearing how I could do so and so in 5 minutes in my beloved old JavaScript way. Yet, as I came out of it, reading more about it, I appreciate it a lot more.
JavaScript is at a crossroads, I feel we developers need directions and structure. We had endured wave after wave of libraries and frameworks, we have had the impossible high of Angular js, only to realize that Angular js 1.x is and will not be the savior. Because hey, Angular js 2.0 is coming, and it is knocking down Angular 1.x and rebuilding the house up.
And, hey, they are using Typescript.
Happy Typescript-ing!