Super-light error objects.
Inspired by go.
I’m no expert with go, but I have heard three things:
-
go has no heavy try/catch mechanism. We all know that try/catch in JS is slowish – and you can do well without it.
-
go does have a thing called
panic
. You use it when you encounter an error which you absolutely can’t recover from. It just crashes the program and displays a readable message to the developer or user. -
go has no heavy stack traces. That’s mental overhead for the user. If you ask me, I don’t like stack traces with umpty-ump calls to dig through. (If you’ve ever used node streams or RxJS, you know what I mean.) I really prefer a descriptive overview of what went wrong, why it went wrong, what to do next and a read-up link.
Since go programmers like it so, why not try lightweight errors in JavaScript?
$ npm install tiny-error
Native:
throw new Error('Something went wrong.');
//» Error: Something went wrong.
//» at repl:1:7
//» at REPLServer.self.eval (repl.js:110:21)
//» at repl.js:249:20
//» at REPLServer.self.eval (repl.js:122:7)
//» at Interface.<anonymous> (repl.js:239:12)
//» at Interface.emit (events.js:95:17)
//» at Interface._onLine (readline.js:203:10)
//» at Interface._line (readline.js:532:8)
//» at Interface._ttyWrite (readline.js:761:14)
//» at ReadStream.onkeypress (readline.js:100:10)
Tiny:
throw tinyError('Something went wrong.');
//» Error: Something went wrong.
Prefer to stay tiny? Then read on.
tiny-error is a maker function*. It creates a new object based on Error.prototype
, but doesn’t invoke the Error
constructor directly – thus saving us from creating a stack trace.
It’s a simple idea – so usage is simple:
const tinyError = require('tiny-error');
tinyError('Oops!');
//» { [Error: Oops!] message: 'Oops!' }
tinyError({message: 'Oops!', myErrorCode: 7});
//» { [Error: Oops!] message: 'Oops!', myErrorCode: 7 }
throw tinyError('Oops!');
//» Error: Oops! (Output depends on how your engine presents errors.)
There is still power behind this simplicity. Just enough to keep it easy to use but still flexible:
throw tinyError({
prefix: '[my library] ',
message: 'Curses! Try once more.',
});
//» Error: [my library] Curses! Try once more.
const myError = tinyError({prefix: '[my library] '});
throw myError('Curses! Try once more.');
//» Error: [my library] Curses! Try once more.
throw myError('Oh no. Not again!');
//» Error: [my library] Oh no. Not again!
* maker function – a term I coined together for a function that creates an object. Not an instance of a class (that’s a factory). Not an instance of a specific class (constructor). Just an object. If there is another word for that, great! Tell me in an issue please.
A shortcut to tinyError({message: message})
.
Parameters:
{String} message
An error maker.
We return an {Error}
if args
contains a {String} args.message
. Otherwise we return a curried function. So these are equivalent:
tinyError({
prefix: '[my library] ',
myCode: 2,
prototype: TypeError.prototype,
message: '`something` should be a number.',
});
const myError = tinyError({prefix: '[my library] '})
myError({
myCode: 2,
prototype: TypeError.prototype,
message: '`something` should be a number.',
});
const argumentError = myError({myCode: 2, prototype: TypeError.prototype});
argumentError('`something` should be a number.');
All args
are just copied to the target object – except three special-cased:
Parameters:
-
{Function} args.prefix
we’ll prepend it to themessage
-
{Function} args.suffix
we’ll append it to themessage
-
{Function} args.prototype
will be used as prototype instead ofError.prototype
Keep in mind that some properties like message
and name
will be treated specially by Error.prototype
.