CHROMABITS

2 minutes

I just finished pushing a new set of updates to Ensure.js! Now all tests are run through the mocha framework and cover about 99% of the code. However, the big news in this release is the addition of record types.

Record Types

Languages like C++, Hack and Haskell have nice syntax for data types that hold information. You might know them as Structs, Shapes or Records.

I have been playing with both Haskell and Hack recently and I thought that it would be nice to have something similar in JavaScript. So I decided to build upon the methods already provided by Ensure.js and add Record Types (inspired from Haskell)

Ensure.js provides an emulation of this format. I say emulation because it is not analyzed statically like other languages and they might have some behavior differences.

However, it can still be useful for adding some validation to certain objects in your application. Instead of blindly assuming that a certain variable of an object is of a certain type you can use Ensure Records which automatically perform these checks for you.

Please note that if performance is important, it is always faster to just use regular objects due to the fact that all checks are performed at runtime.

New methods:

EnsureRecord(spec)

spec: The spec is an object specifying the types of each variable in the record, where the key is the name of the property and the value the type to expect.

EnsureRecordType(values): (Name depends on the name given to the type, see example)

values: The values being applied to the instance being instantiated. Will throw an error if the types do not match the spec

Example:

var ensure = require('ensure'),
    EnsureRecord = ensure.EnsureRecord;

// First, we create our person type
var Person = new EnsureRecord({
        firstName: String,
        lastName: String,
        age: Number
    });

// Then we create an instance by providing its values
var bob = new Person({
        firstName: "Bob",
        lastName: "Lulz",
        age: 20
    });

console.log(bob.firstName)
>>> "Bob"

// Note that if we try to brake the spec, we get an error
var alex = new Person({
        firstName: "Bob",
        lastName: "Lulz",
        age: "Old"
    });
>>> [TypeException]

// Same with setters:
bob.name = [1, 5, 7];
>>> [TypeException]

Hopefully this will help with writing or debugging with your application. The next release goal is to add different modes (“strict”, “production”) that can be set through a settings object.

As usual, the code is on github: https://github.com/etcinit/ensure

Update: Version 0.4.0 contained a bug when using multiple record properties (like in the example). This bug is now fixed on version 0.4.1


1 minute

These are some SCSS mixins I use on most of my projects. I’ll be adding more eventually. They are spread all over my projects.


4 minutes

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

Logo

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. ;)

…or you can find more in the archives.

CHROMABITS
Copyright © 2015-2021 - Eduardo Trujillo
Except where otherwise noted, content on this site is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) license.
Site generated using Gatsby.