edit 16 Nov 2014

Simplified Error Throwing in JavaScript

Throwing errors is hard. Bad errors give you useless information and mislead you. Good errors help you debug your code and suggest possible fixes. I highly recommend you to read a post by Nicholas Zakas on this subject: The Art of Throwing JavaScript Errors Part 1 (why throw and when to throw) and Part 2 (what to throw). Today I would like to discuss practical part of throwing errors.

JavaScript is a very flexible language. As my experience grows my code tend to be more elegant and concise. I try to express more in less. I often use functional programming concepts like currying (see also Why Ramda?) and shortcuts of conditionals with boolean operators (&& and ||, to get more sense about using JavaScript logical operators as conditionals check out this article by Addy Osmani).

I used to read and write code like this:

var port = process.env['PORT'] || 3000;
DEBUG && console.log('Port is', port);

But how do we usually throw errors? For example, we might want to check that required environment variable is set:

var port = process.env['PORT'];

if (!port) {
    throw new Error('PORT is not specified');
}

As you may know, JavaScript have expressions and statements. Axel Rauschmayer in Expressions vs Statements tells us:

Wherever JavaScript expects a statement, you can also write an expression. […] The reverse does not hold: you cannot write a statement where JavaScript expects an expression.

One of the disadvantages of throw is that it is not an expression and you can’t use it in expression context:

var port = process.env['PORT'] || throw new Error('PORT is not specified');
// SyntaxError: Unexpected token throw

That bothered me so much that I decided to just wrap throw in a function (so that it becomes an expression) and drop it into npm module (on GitHub) to reuse in my projects:

var thr = require('throw');

var port = process.env['PORT'] || thr('PORT is not specified');

It is very simple module yet extremely useful. It also utilizes printf-like arguments and you can get rid of string concatenation when constructing error messages:

function getEnvVar(variableName) {
    return process.env[variableName] || thr('Environment variable "%s" is required', variableName);
}

var parsed = parse(input) || thr('Could not parse', input);

function firstMatch(regex, input) {
    var match = regex.exec(input) || thr('%s does not match %s', input, regex);
    return match[1];
}

Maybe it help you too.

Currently custom error types are not supported in node-throw, but they may eventually (file an issue with use case or just send me a pull request).

Some additional links:

Have a nice day!