1

I have a promise-based library (for Node.js 0.10 - 6.x) with a method that rejects with an Array.

When using Bluebird it results in a warning: a promise was rejected with a non-error.

Wrapping the array into a custom error type is easy, but I want to avoid breaking the library's backward compatibility.

Is it possible to implement such an object that could be used as an array, while being seen by Bluebird as an Error object at the same time?

extras

When inheriting from Error I use the following helper for compatibility with Node.js 0.10 - 0.12:

function inherits(child, parent) {
    child.prototype.__proto__ = parent.prototype;
}

And looking at the Bluebird source, maybe there is a way to circumvent its verification somehow:

Promise.prototype._rejectCallback =
function(reason, synchronous, ignoreNonErrorWarnings) {
    var trace = util.ensureErrorObject(reason);
    var hasStack = trace === reason;
    if (!hasStack && !ignoreNonErrorWarnings && debug.warnings()) {
        var message = "a promise was rejected with a non-error: " +
            util.classString(reason);
        this._warn(message, true);
    }
    this._attachExtraTrace(trace, synchronous ? hasStack : false);
    this._reject(reason);
};
vitaly-t
  • 24,279
  • 15
  • 116
  • 138

2 Answers2

0

Javascript don't permits real multiple prototypal inheritance.

You can "extend" Error but the subclass can't be both instanceof an Error and an Array.

If Bluebird use duck-typing you can try to subclass Array object and simulate Error behavior (interface and and properties), but this depends strongly of Bluebird error-check implementation.

I think is better and robust to wrap the array value into an Error property/attribute.

Dario
  • 3,905
  • 2
  • 13
  • 27
  • `is better and robust to wrap the array value into an Error` - as i stated, the main reason I asked the question is to avoid breaking backward compatibility. – vitaly-t Jun 16 '16 at 17:14
  • So you can try to subclass Array with Error interface (like trace property, etc). Looking at Bluebird source it don't use `instanceof Error`. But you can have issues in the future if they change it. – Dario Jun 16 '16 at 17:21
-1

So long as your environment allows subclassing Error, yes!

I asked about something similar while extending errors to create my own subtypes, which is essentially what you want to do. In fact, I've done something similar to create HTTP-specific errors that include the response's status code.

Assuming your environment does allow class SubError extends Error (and there is a workaround if not), you simply do:

class ErrorWithData {
  constructor(msg, data = []) {
    super(msg); // this changes with the workaround
    this._data = [].concat(data); // make a copy for safety's sake
  }

  get data() {
    return this._data;
  }
}

If you're in an older browser that does not allow you to subclass Error, you can use the shim class from @Mosho's answer and replace extends Error in that example with extends ErrorClass.

NodeJS will allow you to extends Error from v4 and on, with v6 having correct/full support for it. Earlier versions require Mosho's workaround.

Community
  • 1
  • 1
ssube
  • 47,010
  • 7
  • 103
  • 140
  • I've just updated my question - it is specifically for Node.js (0.10 - 6.x) – vitaly-t Jun 16 '16 at 17:02
  • Some of those allow `extends Error`, some don't. Per https://kangax.github.io/compat-table/es6/, v4 and v5 require `use strict` (incorrectly) and v6 allows subclassing Error in general, but v0.10 and v0.12 will not. – ssube Jun 16 '16 at 17:07
  • I already use a shim for sub-classing under Node.js 0.10 - 0.12, it works fine. I assume it can be done there also? :) `function inherits(child, parent) { child.prototype.__proto__ = parent.prototype; } ` – vitaly-t Jun 16 '16 at 17:09
  • I believe `Error` has some extra properties (like the stack trace) that will be lost if you simply copy the prototype. You should try it and see. – ssube Jun 16 '16 at 17:11