Chapter 14. ECMAScript-2015/2016 Solutions Today

I cannot count the number of times I have mentioned upcoming versions of JavaScript in this book, rest assured that it's a large number. It is somewhat frustrating that the language is not keeping pace with the requirements of application developers. Many of the approaches we've discussed become unnecessary with a newer version of JavaScript. There are, however, some ways to get the next version of JavaScript working today.

In this chapter we'll look at a couple of these, specifically:

  • Typescript
  • BabelJS

TypeScript

There is no shortage of languages that compile to JavaScript. CoffeeScript is perhaps the best known example of one of these languages, although the Google web toolkit that compiles Java to JavaScript was also once very popular. Never ones to be left behind or use somebody else's solution, Microsoft released a language called TypeScript in 2012. It is designed to be a superset of JavaScript in the same way that C++ is a superset of C. This means that all syntactically valid JavaScript code is also syntactically valid TypeScript code.

Microsoft itself is making heavy use of TypeScript in some of its larger web properties. Both Office 365 and Visual Studio Online have significant code bases written in TypeScript. These projects actually predate TypeScript by a significant margin. The transition from JavaScript to TypeScript was reportedly quite easy due to the fact that it is a superset of JavaScript.

One of the design goals for TypeScript was to make it as compatible as possible with ECMAScript-2015 and future versions. This means that TypeScript supports some, although certainly not all, of the features of ECMAScript-2016, as well as a healthy chunk of ECMAScript-2015. Two significant features from ECMAScript-2016 which are partially supported by Typescript are decorators and async/await.

Decorators

In an earlier chapter we explored aspect oriented programming (AOP). With AOP we wrap function with interceptors. Decorators offer an easy way of doing this. Let's say that we have a class which dispatches messages in Westeros. Obviously there are no phones or internet there, so messages are dispatched via crows. It would be very helpful if we could spy on these messages. Our CrowMessenger class looks like the following:

class CrowMessenger {
  @spy
  public SendMessage(message: string) {
    console.log(`Send message is ${message}`);
  }
}
var c = new CrowMessenger();
var r = c.SendMessage("Attack at dawn");

You may note the @spy annotation on the SendMessage method. This is simply another function which intercepts and wraps the function. Inside of the spy we have access to the function descriptor. As you can see in the following code, we take the descriptor and manipulate it to capture the argument sent to the CrowMessenger class:

function spy(target: any, key: string, descriptor?: any) {
  if(descriptor === undefined) {
    descriptor = Object.getOwnPropertyDescriptor(target, key);
  }
  var originalMethod = descriptor.value;

  descriptor.value =  function (...args: any[]) {
    var arguments = args.map(a => JSON.stringify(a)).join();
    var result = originalMethod.apply(this, args);
    console.log(`Message sent was: ${arguments}`);
    return result;
  }
  return descriptor;
}

Spys would obviously be very useful for testing functions. Not only can we spy on the values here but we could replace the input and output to the function. Consider the following:

descriptor.value =  function (...args: any[]) {
  var arguments = args.map(a => JSON.stringify(a)).join();
  var result = "Retreat at once";
  console.log(`Message sent was: ${arguments}`);
  return result;
}

Decorators can be used for purposes other than AOP. For instance, you could annotate the properties on an object as serializable and use the annotations to control custom JSON serialization. It is my suspicion that decorators will become more useful and powerful as decorators become supported. Already Angular 2.0 is making extensive use of decorators.

Async/Await

In Chapter 7, Reactive Programming, we spoke about how the callback nature of JavaScript programming makes code very confusing. Nowhere is this more apparent than trying to chain together a series of asynchronous events. We rapidly fall into a trap of code, which looks like the following:

$.post("someurl", function(){
  $.post("someotherurl", function(){
    $.get("yetanotherurl", function(){
      navigator.geolocation.getCurrentPosition(function(location){
        ...
      })
    })
  })
})

Not only is this code difficult to read, it is nearly impossible to understand. The async/await syntax, which is borrowed from C#, allows for writing your code in a much more succinct fashion. Behind the scenes generators are used (or abused, if you like) to create the impression of true async/await. Let's look at an example. In the preceding code we made use of the geolocation API which returns the location of a client. It is asynchronous as it performs some IO with the user's machine to get a real world location. Our specification calls for us to get the user's location, post it back to the server, and then get an image:

navigator.geolocation.getCurrentPosition(function(location){
  $.post("/post/url", function(result){
    $.get("/get/url", function(){
   });
  });
});

If we now introduce async/await, this can become the following:

async function getPosition(){
  return await navigator.geolocation.getCurrentPosition();
}
async function postUrl(geoLocationResult){
  return await $.post("/post/url");
}
async function getUrl(postResult){
  return await $.get("/get/url");
}
async function performAction(){
  var position = await getPosition();
  var postResult = await postUrl(position);
  var getResult = await getUrl(postResult);
}

This code assumes that all async responses return promises which are a construct that contains a status and a result. As it stands, most async operations do not return promises but there are libraries and utilities to convert callbacks to promises. As you can see, the syntax is much cleaner and easier to follow than the callback mess.

Typing

As well as the ECMAScript-2016 features we've mentioned in the preceding section, TypeScript has a rather intriguing typing system incorporated into it. One of the nicest parts of JavaScript is that it is a dynamically typed language. We've seen, repeatedly, how, not being burdened by types has saved us time and code. The typing system in TypeScript allows you to use as much or as little typing as you deem to be necessary. You can give variables a type by declaring them with the following syntax:

var a_number: number;
var a_string: string;
var an_html_element: HTMLElement;

Once a variable has a type assigned to it, the TypeScript compiler will use that not only to check that variable's usage, but also to infer what other types may be derived from that class. For example, consider the following code:

var numbers: Array<number> = [];
numbers.push(7);
numbers.push(9);
var unknown = numbers.pop();

Here, the TypeScript compiler will know that unknown is a number. If you attempt to use it as something else, say as the following string:

console.log(unknown.substr(0,1));

Then the compiler will throw an error. However, you don't need to assign a type to any variable. This means that you can tune the degree to which the type checking is run. While it sounds odd, it is actually a brilliant solution for introducing the rigour of type checking without losing the pliability of JavaScript. The typing is only enforced during compilation, once the code is compiled to JavaScript, any hint that there was typing information associated with a field disappears. As a result, the emitted JavaScript is actually very clean.

If you're interested in typing systems and know words like contravariant and can discuss the various levels of gradual typing, then TypeScript's typing system may be well worth your time to investigate.

All the examples in this book were originally written in TypeScript and then compiled to JavaScript. This was done to improve the accuracy of the code and generally to save me from messing up quite so frequently. I'm horribly biased but I think that TypeScript is really well done and certainly better than writing pure JavaScript.

There is no support for typing in future versions of JavaScript. Thus, even with all the changes coming to future versions of JavaScript, I still believe that TypeScript has its place in providing compile time type checking. I never cease to be amazed by the number of times that the type checker has saved me from making silly mistakes when writing TypeScript.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset