Monday, February 8, 2016

TypeScript What/Why/Who/Where/When

Using TypeScript instead of JavaScript can really help to develop and maintain medium to large applications. In this post I'd like to go over some of the situations where I think TypeScript would be beneficial by answering the What/Why/Who/Where/When of TypeScript.

What

Let's start with "what" since you need to know what TypeScript is before we can start. TypeScript is a typed superset of JavaScript that compiles down to plain old JavaScript. What this means is that TypeScript is JavaScript with a few features added, such as static typing. This means that you can specify what type a variable or parameter to a function is. TypeScript has a number of built in types: string, number, boolean, array, enum, any, void. In addition you can create your own types using interfaces, classes and enums.The benefits of static typing are numerous and will be discussed in the "Why" section below.

In addition, TypeScript also has support for many of the new features in the ECMAScript 6 specification such as modules, classes and arrow functions (modules are like namespaces or packages). These will get compiled down JS that is compatible with lesser versions of JS so you can use them in older browsers.

Why

This is the most important question. Why use TypeScript at all. JavaScript is just fine, right?

Well, the problem with JS is that it's very loosely typed (you could argue that's also one of it's strengths). For example, you can create a variable and set it to a string, then in the next line of code set it to a number, then set it to an object. Variables don't have types in JS.

Same with function parameters. In all actuality function parameters are just a convenience in JS. You can pass as many or as few parameters as you like to a function and JS won't care (the inside of the function may care, but not JS).

Same with objects. A JS object is just an associative array, or hash table, or dictionary, or whatever you want to call it. JS objects have no definite shape.

While the absence of typing can sometimes be a very powerful tool, it can also cause a lot of confusion. When writing large applications, using types gives you piece of mind. Once you get to the point where you can't keep the entire application in your head, typing provides protection and knowledge.

First of all it's like having a set of built in unit tests that get run every time you compile. We can all agree that it's better to find problems earlier rather than later at runtime. Would you rather have the compiler tell you exactly where the problem is, or step through your code in the debugger?

Secondly, all you have to do is look at a function's parameters and their types to know exactly what the function expects. Without it you have to look at the function body to know what the function is expecting, or write very good comments. There's no need to write comments if you can look at a variable or parameter and see what its type is. Its self documenting.

Lastly, TypeScript lets your IDE give you better tooling support. It's very hard for an IDE to give you auto complete and auto suggest information when using an untyped language such as JS. For example, it has no idea what types the parameters to a function are, therefore it can't tell you for certain what it expects. Same with objects; it has no way of knowing what fields an object contains. But once your IDE knows about the types of variables and parameters it can give you all kinds of help. It's another form of documentation. You also get better refactoring and usage finding support.

TypeScript also has what are known as type definition files. They provide type information about external JS libraries. That means you get all the tooling support you would expect for your favorite JS libraries including jQuery, Angular, Lodash, etc. (there a TD files available for nearly every popular library out there). No more going to look up documentation because you forgot the signature of a function call in one of these libraries, it's right there at your fingertips, including the types that the function parameters expect.

Who

Now that we know what TypeScript is and why you should use it, let's answer the question of who TypeScript is for. Anyone can use TypeScript of course. But if you are a Java or C# programmer you will feel right at home with TypeScript. That's because TypeScript bridges the gap between what classical OOP programmers expect and how JS does prototypal inheritance. Behind the scenes TypeScript does all the work of converting classes and modules into JS objects.

I think one of the biggest problems that programmers coming over to JS from languages like Java or C# have is that they just don't understand JS objects and how prototypal inheritance works. When I first started writing JS that was my biggest hurdle. I spent a lot of time and energy trying to make JS objects follow the classical OOP paradigms I was used to. With TypeScript you don't have to worry about that because it supports classical OOP.

Even if you are a JavaScript programmer you might want to consider using TypeScript for larger sized projects just to get better tooling in your IDE. It's also going to make it easier in a team environment for other team members to read and understand your code. Remember, TS is JS so you don't have to use every feature in TypeScript all the time. Just use the pieces you want and ease into it. I recently worked on a project with a JavaScript programmer and convinced him to use TypeScript just to get better documentation from type definitions. By the end of the project he also became a fan of static typing and plans to use TypeScript from now on.

Where

You can use TypeScript anywhere that you use JS. That includes single page applications (SPAs) in the browser or Node.js applications. Since TypeScript compiles to plain JS it can be used in any browser that supports JS. You can even start using the ES6 features that TypeScript supports now rather than waiting until all of the browsers get enough support that you can specifically target ES6.

When

Should one use TypeScript all the time? I don't think so. Yes, you heard me right. I like writing TypeScript but there are cases when it's overkill, I'll be the first to admit that. My recommendation, and the rule of thumb I use, is when I can't keep everything in my head anymore then I switch to TypeScript. For me that's when the code starts to take up more than a page of code or I start breaking my code into multiple files. If I can't see it all then I have to spend time moving around looking for things which slows me down. It's also going to make it harder for someone else to read your code.

Remember the golden rule of programming: Code is written for people to read, not computers.

Tuesday, December 1, 2015

Knockout with TypeScript - Observable Arrays

In my first post about using Knockout with TypeScript I talked about the basics of using these two together. This time I want to look at using Knockout's observable arrays. Observable arrays allow you to track changes to arrays, like adding or removing elements. Then you can use a foreach binding in your markup to output the elements of the array.

A lot of times your application will have lists of items that will grow or shrink depending on user interaction. For this example we'll expand upon the first post and create a list of tasks. We'll create an observable array and then output it onto the page.

First let's define the Task class. It has task name, percent complete and is complete fields.

class Task {
    public taskName = ko.observable("");
    public pctComplete = ko.observable("0");
    public isComplete: KnockoutComputed<boolean>;
    constructor() {
        this.isComplete = ko.computed(() => this.pctComplete() === "100");
    }
}

Now let's take a look at the view model for our app. It has app name and tasks fields.

class AppViewModel {
    public appName = "Task List";
    public tasks = ko.observableArray<Task>();
}

Notice that the "tasks" field is defined as an observable array of Task objects. That means it is now being tracked by Knockout so whenever we add another task to the list it will update the page. The next thing we need is a way to add a task to the array. Let's create addTask and reset functions.

class AppViewModel {
    //...
    public addTask(): void
    {
        var task = new Task();
        task.taskName("Task " + this.tasks().length);
        this.tasks.push(task);
    }
    public reset(): void
    {
        this.tasks([]);
    }
}

In our addTask function we create a new Task object, set its name to the length of the tasks array, then add it to the end of the array using push(). Notice that to get the underlying array from a Knockout observable you have to execute the tasks function, e.g. tasks(). Just like any other observable it's a getter/setter.

We also added a reset function. This removes all of the tasks from the array by setting the tasks property to an empty array.

NOTE: There are some methods on the observable array object such as push() and pop(), which makes it seem like you're dealing with an actual array, but you're not. It is an object that wraps an array. This can get a little confusing at first, but you just need to remember that if you want to directly access the array you need to get it from the property first. Be careful there also! You must use the push() method of the observable object, not the underlying array, or it won't be observed by Knockout. My advice is don't access the underlying array unless you need something that the observable can't give you, like the length of the array.

Now let's go and write some markup that will display the task list on our page.

<body>
    <h1 data-bind="text: appName"></h1>
    <button data-bind="click: addTask">Add Task</button>
    <button data-bind="click: reset">Reset</button>
    <div data-bind="foreach: tasks">
        <div>
            <input type="text" data-bind="value: taskName" />
            % Comp:<input type="number" min="0" max="100" step="1" data-bind="value: pctComplete" />
            <input type="checkbox" data-bind="checked: isComplete" disabled />Completed
        </div>
    </div>
</body>

In our markup we define two buttons with click events. One calls the addTask() function in our view model and the other calls reset(). Next we define a div element with a foreach binding set to the tasks array. Now everything inside that div will be repeated for each Task object in the array.

Notice that when inside of a foreach we are in the context of the current element of the array. Therefore we can get the name of the current task by using "value: taskName" as well as the other properties of the Task object.

OK, we have everything we need so let's try it out. If we click the Add Task button a new task will appear on the page with the name "Task 0". If we click the button again another task will appear and so on.

Now change the percent complete of one of the tasks to 100. The completed checkbox will become checked because of our isComplete computed observable.


If you click the Reset button all of the tasks will be removed and the page updated.

Observable arrays in Knockout make it easy for us to create dynamic lists if elements on a page. With only a few lines of code we were able to create an interactive list of tasks. Just remember, an observable array object is a wrapper over a JavaScript array, not an array itself.

<jmg/>

Tuesday, October 6, 2015

Knockout with TypeScript

I write a lot of small single page apps and games using TypeScript. Even with games there is often a need to interact with input fields on the page, for example to allow the user to change settings or show a help panel.

In the past I have used Angular to do that. But the more I used Angular the more I felt like I was wasting a bunch of time fighting with the framework. Angular, in my opinion, is too heavy for small apps and introduces too much complexity and overhead. I love its templating features but don't like being locked into its way of doing things. It's like driving a semi truck when all I need is a compact car.

So I started looking around for a replacement and soon found that I liked Knockout.js. It's really easy to use and doesn't force you to use a monolithic framework. I found it to work excellently for the size of apps I'm usually writing.

Today I thought I would write about the experience I've had making Knockout and TypeScript work nice together. There is a type definition file in the Definitely Typed package for KO that gives you all of the tooling you need (there's a Nuget package available), so right out of the gate you're getting a better experience than using plain JavaScript. However, all of the online documentation for KO is for JavaScript so you need to make a few modifications to optimize it for TypeScript.

KO relies heavily on view models, which are just plain objects that KO uses to interact with the view. The view model can have constant values, observable values, or computed values. Constant values are object members that aren't tracked, therefore if you change them the view won't get updated.

Observables are at the heart of KO. These values are properties that track when the value of the property has changed. Therefore if you change its value the view will be notified to update the value. And vice versa; if you change an input in the view it will update the value in the model. You can also add your own handlers to track changes of observables if you want. You create an observable by calling ko.observable() passing it a default value (note: "ko" is the global Knockout object).

Computed values are computed from one or more observables. For example you might want to convert a value to a percentage to display in the view. Like observables computed values are tracked by the view and automatically updated. You create a computed value by calling ko.computed() and giving it a function that computes the value.

Let's take a look at a simple view model. You can use an object literal for a view model, and this may work for very simple ones, but more often than not you'll find yourself needing to define a class instead. I'll explain why a little later.

class ViewModel {
    public appName = "My Application";
    public taskName = ko.observable("");
    public pctComplete = ko.observable("0");
}

Here appName is a constant value, and taskName and pctComplete are observable values. Although I haven't explicitly specified a type for the observables, they are generics and it implicitly defines them as observable of strings (the type is KnockoutObservable<string>).

You're probably wondering why I didn't make pctComplete a number instead of a string. This is one of the areas where KO and TypeScript don't interact too well together. Since JavaScript doesn't know anything about types, neither does KO. You can make an observable of any type, but if you bind it to an input field in your view (even if type=number) it will replace the value with a string. So you might as well save yourself the trouble and always use a string, then convert it as you need to.

OK, great, we have a view model. Now we need to tell KO about it. For that you call ko.applyBindings() passing it an instance of the view model.

var viewModel = new ViewModel();
ko.applyBindings(viewModel);

Now KO will apply the view model to your view. Let's define a view that uses the model.

<h1 data-bind="text: appName"></h1>
<input type="text" data-bind="value: taskName" />
<input type="number" min="0" max="100" step="1" data-bind="value: pctComplete" />

KO makes use of the data-bind attribute to interact with it in HTML. First we're telling it to set the text of the h1 element to whatever the value of appName is in the view model. Then we set the value of the text input element to the value of taskName. Finally we set the value of the number input element to the value of pctComplete.

Now if you were to change any of the values of the input fields the values in the view model will automatically get updated as well.

Lets add a computed field now. Say we want a boolean value called isComplete and it will be set to true if and only if pctComplete is 100.

class ViewModel {
    // ...
    public isComplete: KnockoutComputed<boolean>;
    constructor() {
        this.isComplete = ko.computed(() => this.pctComplete() === "100");
    }
}

Remember earlier when I said you probably want to use a class instead of an object literal? Computed values are the reason why. You can't define computed values in an object literal that reference other properties of the object. Therefore you're going to need to do it in a constructor.

So what we did here was define an isComplete member of the object and type it as a computed boolean value using KnockoutComputed<boolean>. In the constructor is where we define the function behind the computed value. Here we are defining a function that returns true if the value of pctComplete is "100". Note that we need to use parens to get the value of pctComplete. That's because observables are actually property functions that either get or set the value of the property.

Now we can add a checkbox to the view that uses the computed value.

<input type="checkbox" data-bind="checked: isComplete" />

Here we tell the checkbox to become checked whenever isComplete is true. Now if we were to change the value of the pctComplete input to "100" the checkbox would become checked.

Lets look at one more basic feature of KO view models. In addition to the three properties of a view model I mentioned above you may also define functions. Functions are useful for handing click events in your view. Say we wanted to add a reset button, then we would need a function to reset the view model.

class ViewModel {
    // ...
    public reset(): void {
        this.pctComplete("0");
        this.taskName("");
    }
}

Here's the button in the view.

<button data-bind="click: reset">Reset</button>

We create a button and tell KO that on click to call the reset() function in the view model. Now if we click the reset button the pctComplete and taskName fields will be reset.

Those are the basics of using KO with TS. In another post I'll go over some more advanced topics like view models within view models and creating custom elements.

<jmg/>