Oliver Nassar

Type hinting in Javascript using TypeHinter

March 26, 2011

tl;dr

Ensure your arguments are of the proper type:

$('login').addEvent(
    'click',
    function (event) {

        // type hinting/enforcement
        TypeHinter.benchmark('file.js', 'function::anon');
        TypeHinter.check(
            [event, Event]
        );

        // function logic
        event.stop();
        // ...
    }
);

Introduction

TypeHinter is a type hinting/argument enforcing script which helps in the debugging of both server and client side Javascript. It currently provides 5 simple and straightforward methods which allow you to, in alphabetical order:

Background

In setting up one of my first GitHub repo's, I thought TypeHinter.class.js would be a good candidate since it's a pretty simple class/script, works on both client and server stacks, and is good at one specific thing.

Flow

Whenever a function or method is defined, I separate the logic out into two components:

  1. argument validation
  2. function/method logic

Before anything happens in the function/method, I simply check to make sure that the arguments are the exact object types I expect. If this fails, an error is either logged, or thrown.

Example

Before I go into the details of how the script works, I'll show an example:

$('login').addEvent(
    'click',
    function (event) {

        // type hinting/enforcement
        TypeHinter.benchmark('file.js', 'function::anon');
        TypeHinter.check(
            [event, Event]
        );

        // function logic
        event.stop();
        // ...
    }
);

This is a pretty straight forward event handler. Before any of the function logic gets executed, a call is made to TypeHinter.benchmark, with the filename and function name (if it exists) as an argument. If this isn't done, the TypeHinter will throw an error. This is pretty important for debugging, so I figured I'd make it mandatory.

After this, a call to the TypeHinter.check method is made. It can receive an unlimited number of arguments, with each argument an array of mixed objects. So in this case, we have one argument being passed as:

[event, Event]

This contains the event object that was initially passed as the event-handler's callback, as well as a reference to the Event class. As brushed-over initially, the TypeHinter loops over the arguments passed in, and ensures that they are the valid type. Therefore in this case, if the argument passed to the event-handler's callback is a string, array, or not defined (aka. not passed to the function at all), the TypeHinter will throw an error (or simply log it to the console depending on whether you made a call to TypeHinter.strict(false)).

Summary

It's a pretty simple little class. My motivation behind this was through my exposure to nodejs. Parameters are flying around way more often and casually on the server side than on the client side (imo), and this lead to a lot of debugging of parameter types of my part. I found this helpful, especially when dealing with external data-sets such as APIs and storage-systems.

More Examples

Passed in argument must be a String or Object

function(arg) {

    // type hinting/enforcement
    TypeHinter.benchmark('file.js', 'name');
    TypeHinter.check(
        [arg, String, Object]
    );

    // function logic
    // ...
}

First argument only is checked against being a String or an instance of the CustomClass class

function(arg1, arg2) {

    // type hinting/enforcement
    TypeHinter.benchmark('file.js', 'name');
    TypeHinter.check(
        [arg1, String, CustomClass]
    );

    // function logic
    // ...
}

First argument must be a String or Object; the second argument must be passed, but can be of any type (excluding undefined)

function(arg1, arg2) {

    // type hinting/enforcement
    TypeHinter.benchmark('file.js', 'name');
    TypeHinter.check(
        [arg1, String, Object],
        [arg2]
    );

    // function logic
    // ...
}

First argument must be a String or Object; the second argument can either be a String or undefined (aka. not passed)

function(arg1, arg2) {

    // type hinting/enforcement
    TypeHinter.benchmark('file.js', 'name');
    TypeHinter.check(
        [arg1, String, Object],
        [arg2, String, undefined]
    );

    // function logic
    // ...
}

Neither arguments have any restrictions (eg. won't be checked)

function(arg1, arg2) {

    // type hinting/enforcement
    TypeHinter.benchmark('file.js', 'name');
    TypeHinter.check();

    // function logic
    // ...
}