Throwing strings instead of Errors

Since we can throw anything with the throw keyword in Javascript, can't we just throw an error message string directly?

Does anyone know any catch in this?

Let me add some background to this: Very often, in the JavaScript world, people rely on parameter checking as opposed to using the try-catch mechanism, so it makes sense to only throw fatal errors with throw. Still, to be able to catch some system Errors, I have to use a different class for my own errors and instead of creating a subclass of Error, I think I should just use String.


Solution 1:

While it is okay possible to throw any value, it is generally considered poor form to throw anything other than an instance of Error or one of its subclasses. There are several reasons for this:

  1. Catching code may expect the thrown object to have the usual message, stacktrace, and name properties that appear on Errors.
  2. Lack of a stacktrace makes debugging problematic, especially in the case of uncaught exceptions / unhandled rejections. E.g. Debugging an "Uncaught [Object object]" error can be particularly painful.

Solution 2:

Yes, you can throw other values, but it's not a good practice.

Does anyone know any catch in this?

A string is not an error object, and does not convey any useful debugging information. Devtools rely on that, such as the file and line where the error was created, the stacktrace at the throw location etc, which are available as properties on Error objects.

Whenever you think of throwing a primitive string value, throw a new Error("<the string>") instead.

Solution 3:

You can throw errors with messages, you know.

try {
    throw new Error("This is an error");
} catch (e) {
    alert(e.message); // This is an error
}

But you can actually throw strings:

try {
    throw "This is an error";
} catch (e) {
    alert(e); // This is an error
}

Solution 4:

As others have mentioned above, if you are not throwing an Error object, then you must have try/catch blocks to trap these objects and handle them appropriately or else be in a world of hurt for debugging.

However, when it comes to throwing Errors for non-error handling purposes like controlling program flow, this may be a helpful way to utilize throw without an Error.

When using throws to control program flow, it can be inefficient in any language as the runtime will often do a lot of heavy lifting to unwind call stack information and serialize the data so its available to the user land scope. By avoiding Error creation, you can avoid this performance hit. The key is that you must have a handler up the call stack that knows how to handle this situation. For instance if you throw {isHardStop: true, stopCode: SOME_CODE} and design the handlers to detect this, you may be able to flatten out some of your code or choose cleaner syntax.

Your handler for this ladder case could be structured like:

try { ... } catch(thr) {
    if(!thr){
       // Is not Error or Json - Handle accordingly
    } else if(thr.isHardStop){
       // Handle the stop
    } else {
       // Most likely a real error. Handle accordingly
    }
}

Solution 5:

Although you can throw any type of data that you’d like, this is not optimal when debugging. A JS Error object contains all kind of information regarding the Error and a message. Whereas a string can only contain a message.

This additional information includes:

  1. fileName: from which file the error was thrown
  2. Linenumber: from which line the error was thrown
  3. stacktrace: from which function the error was called

Here is for example a stacktrace from chrome devtools:

enter image description here