Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How I Learned to Stop Worrying and Love TypeScript

DZone's Guide to

How I Learned to Stop Worrying and Love TypeScript

When TypeScript first arrived from the mind of the legendary C# inventor, there were actually some who thought it would ruin JavaScript. One person now thinks the opposite.

· Web Dev Zone
Free Resource

Should you build your own web experimentation solution? Download this whitepaper by Optimizely to find out.

When I started writing this article, the original working title was “Angular Didn’t Ruin JavaScript, TypeScript Did.” However, that’s not really the conclusion of this article (and rather “link-baity” after all). I love you all entirely too much to do that to you.

But let me start by saying something a bit incendiary that explains why I originally thought that TypeScript did in fact ruin JavaScript.

JavaScript, Welcome To Hell

I remember when TypeScript was first released, I watched a video with Anders Hejlsberg doing some demonstrations of types, classes, interfaces, and other such static language fare, all of which was transpiling down to just plain JavaScript.

And I thought, “No. No NO NO NO NOO NOOOOOOOO!”

I Hate Types

I’ve always loved JavaScript. From the moment I first set eyes on it. The first language that I learned was ActionScript and then eventually C#. And I hated C#. Well, not the syntax of C#, but I definitely wanted to see the compiler rot in hell.

It seemed to me that the compiler was unnecessarily dumb.

Consider the following…

var i = 1;
var x = null; 

Console.WriteLine(i == x);

// ERROR: Cannot assign <null> to an implicitly-typed variable

Really? There’s only one null value in the language, and you can’t deal with it?

“Well, no Burke. Because you have to know what type to set to null in case it’s not null at a later time.”

I’m not sure why we can’t just deal with that when we are actually interested in a type, but ok, I’ll conceed that.

var i = 1;
int x = null; 

Console.WriteLine(i == x);

// ERROR: Cannot convert null to 'int' because it is a non-nullable value type

You can’t set the value of an integer to null without first saying that it’s nullable. Too much manual labor has already been required of me at this point. I’m trying to solve real problems here, and I don’t have time to hand-hold the computer through basic concepts such as numbers. I’m sure there’s a good academic reason for nullable types, but I don’t care.

idontcare_spongebob

I spent so much of my time as a C# developer just fighting types. That’s all. And that’s not even considering things like reflection, a trivial affair in JavaScript that equates to an absolute circus in C#.

My fundamental problem with typed systems is that they force you to know – in advance – the exact format of every incoming data structure you’re going to be working with, which is often impossible.

Consider a scenario where you have a database that accepts a null type in an integer field. Let’s say you’re working with a module that you cannot change that is using non-nullable integer types. How do you handle the null scenario? Usually, it’s like this:

db.propertyToUpdate = sealedModule.fieldINeed == -1 ? 
    null : sealedModule.fieldINeed;    

At this point, besides feeling like a complete failure in life, you’re also incurring technical debt as you are forced to mutilate your code to please the compiler.

So if strong typing is so awful, why do so many developers like it? In a word – Increased Productivity.

Increased Productivity

Ok, that was two words.

I know I just made a case for how types cause developers to incur technical debt and then I said that typed languages increase productivity and that’s more than just a smidge contradictory, but it’s one of those double-edged sword thingies.

Types are what make an IDE more than just a text editor. More often than not, we’re working with code that we did not write, most commonly via use of a framework. The framework has an API we (at least initially) know nothing about. This means that in order to be productive with a framework, you have to not only know how to code, but also have mastered someone else’s code. Seems kind of unfair, doesn’t it?

And learning an entire framework is no small task. After 5 years, I still find myself in the jQuery docs and that’s not even a complex or large API surface. When you’re talking about something as large as the .NET framework, or Cocoa, there is simply no way to know it all without years of experience.

Let’s take just a String in C#. According to the official documentation for .NET 4.5, The String class has 8 constructors and 120 methods! That’s not even including extension methods or operators.

By contrast, the JavaScript String object has 1 constructor and 21 methods. Even with just 21 methods, I still find myself looking them up from time to time.

This is where the IDE steps in and makes it possible to use frameworks as enormous as .NET. I don’t need to refer to the string documentation, I just need to start using a string. When I do, the IDE will let me know what methods I can use, and will tell me what they do, without me ever leaving the editor and losing context.

string-intellisense

And this is where we finally get to TypeScript.

Up until now, strongly typed languages were an all or nothing bag. TypeScript is different. It brings the best parts of typing – specifically the increased productivity via IDE integration – and leaves the ridiculous casting part as optional. I didn’t fully grasp the power of this until recently when I was doing some NativeScript development.

The Value Of TypeScript

I’ve been doing a lot of NativeScript work lately, and NativeScript treats TypeScript as a first class citizen – a BFF really. In fact, the entirety of the cross-platform modules in NativeScript (tns_modules) are written in TypeScript. AppBuilder For Visual Studio provides a TypeScript template for NativeScript, so I decided to give it a shot and see what it’s actually like to use TypeScript in Visual Studio.

If I’m writing a simple application in NativeScript, I start with the markup for a page (mobile view). As I do that, Visual Studio prompts me with some events that I can use, such as the oft utilized loaded event in NativeScript. This is done because NativeScript provides a schema defintion to Visual Studio for the markup. But it’s Visual Studio that provides the editor magic. I can also create a TextField without having to remember what the markup is for one.

xml-page

Consider the following code from a NativeScript page which handles the loaded event. This can be written with standard ES5 JavaScript like so…

var viewModule = require('ui/view');

exports.loaded = function(args) {
    var page = args.object;
    greeting = viewModule.getViewById(page, "txtGreeting");
    greeting.text = "Hello Indeed";
}

This is CommonJS, which NativeScript also supports as a first-class citizen. The problem with this is that I frequently find myself going back to the NativeScript documentation to try and remember what properties are on what objects and what objects are passed to which events.

Here is what is happening in this code…

  • The loaded event is defined.
  • A reference to the current page (xml) is obtained.
  • A reference to the TextField is obtained.
  • The text of the TextField is changed to “Hello Indeed”

The problem is that this is just JavaScript and I have to know a lot about NativeScript here. I have to know about the loaded event, I have to know what object the event receives, I have to know how to obtain a reference to the page. I have to know that I need the view module in order to get that reference and I have to know what the method on the view module is and what parameters it needs. Lastly, I need to know what method to call on the control instance to set it’s text.

That’s a lot to have to keep up with and we’re not really doing much. Also, none of this code is checked at design time, so any null object or method references are going to result in an unceremonious application crash.

Now lets re-write this with TypeScript and see how this gets simplified.

Since TypeScript is a first-class citizen in NativeScript, we can re-write this in a .ts file

I’m just going to start under the assumption that I know that I need a loaded event based on what I built in the XML.

export function loaded() {
    //...
};

So far, this looks familiar. Now we just need to know what type of event the loaded function is going to receive. According to the documentation, all events receive an observable. To use an observable, we need to import one.

import * as observable from 'data/observable';
export function loaded(args: observable.EventData) {
    //...
};

If that import looks terrifying to you, then you are just like me. That’s actually ES6 syntax for modules. One of the neat things about using TypeScript, is that it implements quite a bit of ES6 where it can, and uses proprietary syntax where the spec is incomplete or missing.

In this case, we are saying, “Import everything from the observable file and put it all in an object called observable.”

Now watch the magic unfold after we have gotten this far. I know that I need a page reference, so I check the args object.

args-page

I’m given two options – eventData and object. These are the only two properties that are coming in on the event. I can safely assume that object is what I need. Now I need to cast it to a page. I need the Page module to do that, and TypeScript is aware of the type.

import * as page from 'ui/page';

And now I can cast the object to a Page type.

args-to-page

More ES6! I can use the let and const keywords in TypeScript. I could also just use var and that would be fine too. Now that I have the page and TypeScript knows that it’s a page object, I can use the getViewById method to get a reference to the TextField.

get-view-by-id

That returns me a generic view object, which is subclassed by all the UI components. That means I need to cast it to a TextField type.

set-text

There’s a lot going on in that GIF. Notice that I make a mistake and try to set the text via a method. TypeScript catches this for me and points out that this is a property, not a method. Also notice that my import of the TextField type looks a tad funkier than the other imports. That’s because ES6 modules allow you to import any property or method exposed by a module as a single import. This allows you to cherry-pick just want you want from a module.

My favorite thing about all of this is the fact that I know, without a shadow of a doubt, that when I run this, it’s going to work. If not, it’s not going to because I made some stupid mistake. The browser is forgiving. Native applications are not. Errors aren’t just shelled to the console. They result in nasty app crashes and in the case of mobile apps, the app just crashes and doesn’t tell the user anything at all. I’ve always thought this was a horrible user experience.

The Best Part

Now the best part of all this? I can still do this…

var x = 1;
var i = null;
console.log(x === i); // FALSE

HAHA! I win! All of the benefits of the IDE and none of the soul crushing insanity of strongly typed systems. As they say in the sales game, it’s a “win-win.”

Should You Use TypeScript?

It depends.

I think that due to the browsers’ incredibly forgiving nature for your crappy code, you are just fine with plain JavaScript. I’m not convinced that the browser environment demands such stringent expectations of your code. I think you will iterate faster without it to be honest.

However…JavaScript is being written in more and more places, including being used to create native mobile application. NativeScript is just one example. In these cases, I imagine that you would want the power of TypeScript.

I also think that TypeScript encourages you to learn ES6. That’s imperative since ES6 is coming at us at a screaming pace. It’s a pretty big change, and you can’t avoid it forever. TypeScript is a great way to ease into some of the essential ES6 concepts, such as modules.

In any case, TypeScript has made a fan out of me. I know that I prefer to use it in my NativeScript projects, and I’m looking forward to doing more with it, especially as Angular 2 looms on the horizon.

TypeScript support is available today in the AppBuilder Plugin For Visual Studio.

Implementing an Experimentation Solution: Choosing whether to build or buy?

Topics:
javascript ,typescript

Published at DZone with permission of Burke Holland, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}