HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Simple JavaScript precondition checking implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simplejavascriptcheckingimplementationprecondition

Problem

I am writing a JavaScript application and would like to validate function arguments in many places. Most of these checks will be for correct argument types, or numeric values within specific ranges.

Here is a simple function I came up with to check any number of preconditions:

function requires(conditions)
{
    for (var cond in arguments)
    {
        if (typeof cond !== "boolean") throw "Preconditions must be boolean expressions {" + cond + "}";
        if (cond !== true) throw "Precondition failed {" + cond + "}";
    }
}


It would be used like this:

function alertChar(message, index)
{
    requires(
        typeof message === "string",
        typeof index === "number",
        index >= 0,
        index < message.length);

    alert(message.charAt(index));
}


Is there anything conceptually wrong with this simple implementation? Is there a way I can make it lazily evaluate each precondition expression? Is accessing the arguments array inefficient?

Solution

function requires(conditions)
{
    for (var cond in arguments)


Don't use for-in. The problem with for-in is that it runs over prototype properties as well. You might loop through more properties than you expect. Either use a regular loop or convert your iterable into an actual array to access array method.

If you can write in ES6, you can use the rest operator. What it does is put the rest of the arguments into an array. Much like arguments but it's a real array. You have access to all array methods.

function requires(...args){
  args.forEach(...)


if (typeof cond !== "boolean") throw "Preconditions must be boolean expressions {" + cond + "}";
if (cond !== true) throw "Precondition failed {" + cond + "}";


The second condition is overly verbose. The first check weeds conds that are not boolean. Therefore, if it passes that part, cond is a boolean. That means you can simplify if (cond !== true) as if (!cond).

requires(
    typeof message === "string",
    typeof index === "number",
    index >= 0,
    index < message.length);


If you go on with this route of manual type checks, at least hide away the complexity by abstracting the checks away. The following would be more like it. Checks the arguments against the type, and in that order.

require(args, ['string', 'number']);


Additionally, the last 2 checks there are not type checks but more like app-specific logic. Your type checker should not concern itself with those anymore.

Runtime type checks should be avoided as they incur performance penalties as well as cause bloated code. Common practice is to offload this responsibility to development-time and/or build-time tools.

TypeScript and Flow are typed supersets of JS that will let you write in a typed language and whose compilers do type checks for you.

If you prefer vanilla JS, using an editor or IDE that utilizes JSDoc to do basic checks is also an option. I know Visual Studio's Intellisense or Intellij IDEA with the right plugins do this.

Code Snippets

function requires(conditions)
{
    for (var cond in arguments)
function requires(...args){
  args.forEach(...)
if (typeof cond !== "boolean") throw "Preconditions must be boolean expressions {" + cond + "}";
if (cond !== true) throw "Precondition failed {" + cond + "}";
requires(
    typeof message === "string",
    typeof index === "number",
    index >= 0,
    index < message.length);
require(args, ['string', 'number']);

Context

StackExchange Code Review Q#141722, answer score: 3

Revisions (0)

No revisions yet.