Logo
Logo

From type-safe to type-unsafe?

Coming from a world of Object Oriented languages and starting to work on JavaScript projects can be a little bit frustrating some times. You try to think in terms of classes, inheritance, interfaces, namespaces, etc.

The fact is that JavaScript is not classically OO, it uses a prototypical inheritance. It is also an untyped language, which means that variables are not expected and enforced to be of a certain type (no type declarations). However, this hasn?t stopped programmers from trying to emulate classical OOP features in JavaScript. There have been multiple libraries that try to mimic these behaviors as much as possible, and it is definitely possible in some way since we have so many compilers that will take one language such as Ruby or Haskell and convert it into a JavaScript file.

I?m not specifically bothered by the lack of a classical inheritance model, but the lack of type checking really affected the way I code. While this was not the case on small simple projects, on larger applications it really got in the way.

Routine tasks such as validating data as it comes from the user and then being sent back to an API became more difficult, and there is also the factor of human error: If you forget to set a variable JavaScript will not complain a lot and will keep running, in most cases just saying that the variable is undefined, which is definitely not the programmers intent.

Temporal fix

So my solution? Write if statements checking that types, and validation rules are met on multiple parts of my applications. This worked at first, my code was actually catching errors and notifying me of mistakes that I hadn?t noticed before, but then it became a menial task to write and maintain all these checks.

The main two problems with this approach were: - Convoluted: A block of if statements on the top of most functions is not something you would like to see as you are reading through code, and something that adds unnecessary thickness to the code in general. - Performance: Running type checks on runtime can have a performance hit. Thankfully, browsers nowadays are fast enough that this hit is almost unnoticeable.

Say hi to Ensure.js

So this is where Ensure.js comes in: I decided to build a small object for my projects that had some simple common validation rules. Then I started to add more and more, and finally I looked for a way of simplifying all these into one single function:

ensure(object, type, soft = false)

Checking if an object is a String is as simple as:

var hello = "Hello World";

ensure(hello, String, true);
>> true

var number = 1337;

ensure(number, String, true);
>> false

Harder, Better, Faster, Stronger

While the previous examples return a boolean (soft mode), the default behavior is to throw an Error (specifically a TypeException). This means that you don’t need a bunch of if statements for checking if all the parameters of a function are valid:

var sum = function (num1, num2) {
    try {
        ensure(num1, Number);
        ensure(num2, Number);

        return num1 + num2;
   } catch (error) {
        if (error instanceof TypeException) {
            console.log('Invalid parameters');
        } else {
            console.log('Some error: ' + error);
        }
   }
};

“But wait, there’s more!”

Ensure can also do some extra tricks:

Checking if a number is positive:

ensure.isPositiveNumber(-90);
>> false

ensure.isPositiveNumber(0);
>> true

ensure.isPositiveNumber(90);
>> true

Checking if a number is within a range:

var hello = 'Hello';

ensure.isInRange(hello.length, 0, 2);
>> false

ensure.isInRange(hello.length, 0, 7);
>> true

Checking if an object is in an array:

ensure.isIn(23, [20, 21, 22, 23]);
>> true

ensure.isIn(0, [20, 21, 22, 23]);
>> false

(Essentially a nicer version of Array.indexOf)

I found this object to be useful enough that I decided to package it into a library so that my coworkers/friends could use it. It defines itself as a global object on browsers and it exposes a module under node.js.

Huge room for improvement

However, there is still A LOT of room for improvement. This library only fixes the first problem mentioned. Performing type checks during runtime using Ensure can still have a performance effect on your application.

I haven?t really tested yet how bad it is, but in the future I would like to allow developers to enable and disable validation through a setting. This would allow them to run validations and type checking while developing, and then disabled them when the code is going to production so that there is no performance effect. Another important future feature would be to allow some kind of parameter that can say which validations are affected by this setting, so that the library can still be used for validating forms and more.

In the short term, the plan is too add checking for more built-in and complex types, and add more utility functions like checking if all the elements of an array are of the same type. Additionally, test cases, I really need to write tests cases.

You can download the source code on GitHub and start playing with in: https://github.com/eduard44/ensure

Send a pull request if there is some feature or function you would like to add. ;)


Alternative Formats
This post is also available in Markdown: View source