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/>

Wednesday, September 23, 2015

TypeScript vs. JavaScript

Seems like a lot of people want to know what they should use for web development: TypeScript or JavaScript? Well, like anything else it depends on the context. They are two different tools used for two different purposes.

JavaScript is very loose; there is no compiling or type checking. You can quickly make a small app or write some form validation code. There's a lot less typing involved and you don't have to think too much about structure. In these situations using JavaScript is more productive.

TypeScript on the other hand is better suited to large single page application with complex interactions spanning multiple source files. As the number of lines of code increases applications tend to get more complex. This is where TypeScript, with it's type checking and added structure, help you manage the complexity and become more productive.

The graph below illustrates what I'm talking about. Up to a certain point JavaScript is more productive because there's less overhead. But after you pass that point TypeScript becomes more productive because it's easier to manage the complexity.


I can't tell you what the specific lines of code are. For me it's about a page or two of code. My general rule is if you can hold the entire app in your head then use JavaScript, otherwise use TypeScript.

How does TypeScript reduce complexity? As its name implies, types. By giving your variables and parameters types it makes it easier for the compiler to make sure you didn't accidentally use a wrong type, and easier for you to know what the variable represents. It's hard enough even with types to determine what a variable is used for, so why make it harder?

TypeScript also supports classical OOP in the form of classes and interfaces. These are basically your custom types. Classes and interfaces give a more rigid structure to your code. Contrast that to plain old JavaScript objects which have no structure at all. They can be whatever anyone wants them to be and there's no way for you to know with inspecting the contents of the object.

TypeScript provides better tooling for your IDE. In JavaScript it's very hard for your IDE to determine what type a variable or parameter is because, well, it's untyped. With TypeScript the IDE knows exactly what type something is and can tell you. For example, intellisense can tell you exactly what types the parameters of a function expect taking the guesswork out of calling it. It's like built in documentation.

When you compile TypeScript it's like running unit tests on your code. For example, say you changed the signature of a function and forgot to change all the references to it. You immediately know there is a problem and where it is. In my experience this is much faster than running your app, getting an error, looking at the stack trace (if there is one), then finding the errant code.

All of this makes for less things you have to keep in your head. Remember, code isn't written for computers to understand, it's written for humans to understand (otherwise we'd all be writing code in 0's and 1's). 

Even though TypeScript is an extension of and compiles to JavaScript they are two very different tools. Knowing what context to use each in can help you write and maintain your code more efficiently.

Thursday, September 17, 2015

Typescript Function Overloading

Function overloading in TypeScript is a little enigmatic and complicated to learn at first. It doesn't work like traditional overloading in other languages like C# or Java where you just create a new function with the same name but different parameters. Function overloading in TypeScript is more like defining facades for a function.

The reason TypeScript doesn't have traditional function overloading is because JavaScript doesn't support overloading. The reason JS doesn't support overloading is because JS doesn't care about function signatures. You can pass any parameters you want to a function in JS. Therefore you can't define two functions with the same name because it has no way to tell them apart.

As I said, function overloading in TypeScript is more like defining facades or interfaces to a function than overloading. The way it works is you define a function that can handle all of the different parameters that you want to throw at it, just as you would in JavaScript, then define your facades to make it easier to call that function.

An example would make it easier to see how this works. Say we want to have a getter and setter methods with the same name. First let's just write it as one function without any overloads.

class Foo{
    private _bar: string;
    public bar(val?: string): any {
        if (val || val === ""){
            this._bar = val;
        }
        else return this._bar;
    }
}

If a string parameter is passed in it will set the backing variable and return nothing. If no parameter is passed it will return the value of the backing variable. This will work, but the function signature isn't very intuitive or user friendly. So let's add some overloads, or facades, that will make it more apparent how to use it.

class Foo{
    private _bar: string;
    public bar(): string;
    public bar(val: string): void;
    public bar(val?: string): any {
        if (val || val === ""){
            this._bar = val;
        }
        else return this._bar;
    }
}

We've added two signature overloads. Notice that the overload signatures must come before the actual function body. The first is our getter which takes no parameters and returns a string. The second is our setter which takes a string parameter and has a return type of void. Both of these signatures must be compatible with the real function definition's signature.

Let's look at another example. This time we'll make a class called Color and overload the constructor so that you can either pass in a string color identifier or red, green and blue components.

class Color{
    public stringValue: string;
    constructor(def: string);
    constructor(r: number, g: number, b: number);
    constructor(rOrDef: any, g?: number, b?: number){
        if (typeof(rOrDef) === "string"){
            this.stringValue = rOrDef;
        }
        else{
            this.stringValue = "rgb("+rOrDef+","+g+","+b+")";
        }
    }
}

Notice that the first parameter rOrDef is defined as "any" so that it can take a string or number. The g and b parameters are marked as optional. Then we can simply create our two signature facades, one that takes one string parameter, and another that takes three number parameters.

Once you realize that there is no such thing as function overloading in TypeScript that's the key to understanding it. You're actually creating facades that make it easier for someone to call a function that will accept many different types of parameters.

TypeScript Private Constants and Minification

I'm currently working on a TypeScript app that has a lot of private static values inside the classes. They don't need to be visible to the outside world, but making a variable "private static" doesn't mean that it will really hide the variable in the compiled JavaScript. It's merely a hint to the compiler to limit access to the insides of the class. Here's an example:

module TestMod {
    export class TestClass {
        private static privateStatic = "I'm private and static";
    }
}

Compiles to:

var TestMod;
(function (TestMod) {
    var TestClass = (function () {
        function TestClass() {
        }
        TestClass.privateStatic = "I'm private and static";
        return TestClass;
    })();
    TestMod.TestClass = TestClass;
})(TestMod || (TestMod = {}));

As you can see privateStatic is completely accessible outside the object after compilation. If you're writing a library that may be used by JavaScript this isn't good (but I probably wouldn't write a JavaScript library in TypeScript). For me the biggest implication of this is that when you minify your JavaScript those members' names can't be modified. The minifier doesn't know that private static variables will never be accessed from the outside.

After running it through a minifier you get this:


var TestMod;!function(t){var a=function(){function t(){}return t.privateStatic="I'm private and static",t}();t.TestClass=a}(TestMod||(TestMod={}));

As you can see privateStatic was not renamed to a shorter name as you might have wanted.

One way we can remedy this is to move the private static variables up into the module. As long as you don't mark them with the export keyword they will be completely hidden from the outside world.


module TestMod {
    var _privateStatic = "I'm private and static";
    export class TestClass {
        public foo() { return _privateStatic; }
    }
}

Compiles to:
var TestMod;
(function (TestMod) {
    var _privateStatic = "I'm private and static";
    var TestClass = (function () {
        function TestClass() {
        }
        TestClass.prototype.foo = function () { return _privateStatic; };
        return TestClass;
    })();
    TestMod.TestClass = TestClass;
})(TestMod || (TestMod = {}));

Now _privateStatic is assigned to a variable in a closure. If we look at the minified JavaScript you can see that _privateStatic has been changed to "n" giving you better minification.

var TestMod;!function(t){var n="I'm private and static",o=function(){function t(){}return t.prototype.foo=function(){return n},t}();t.TestClass=o}(TestMod||(TestMod={}));

One problem with this technique is readability. Notice that I change the name from privateStatic to _privateStatic. I prefix the variable names with an underscore to make it clear that they are defined outside the class but are still private.

If you have a lot of static variables or constants in a class and you're looking to save some bytes in your minified application you might take a look at using this technique. It may make your code a little harder to read but the trade off is you get a smaller app. 

TypeScript Lambda Gotcha

I came across a little gotcha today in TypeScript that I hadn't thought about before (but should have known better). When you use lambdas syntax, if you don't wrap it in curly braces it returns the result of the expression. In most cases this is probably fine, but not if the caller of your function is looking for a return type. I was using the LoDash _.each() function which allows you to pass back false if you want to break the loop. And unfortunately I was setting a boolean variable in the lambda without using curly braces. So every time I set the variable to false it broke the loop and I got bugs :-(.

For example, here I'm not using braces around my lambda expression, so whenever item.condition is not 1 it breaks the loop.

_.each(items, (item) => item.visible = (item.condition === 1));

This compiles down to:

_.each(items, function(item) { return item.visible = (item.condition === 1); });
See how it inserted a return statement? That's not we wanted!

By simply adding curly braces the return is removed and you get the correct behavior.

_.each(items, (item) => { item.visible = (item.condition === 1); });
It compiles to:

_.each(items, function(item) { item.visible = (item.condition === 1); });

So maybe I should start using braces when I don't want to explicitly return a value. But it looks so much cleaner the other way when you just want to do a simple one-liner. So we'll see...