12

I'm trying to spread an Error so that I can alter the error without affecting the original error.

const error = new Error('Error test');

const freeError = {...error};
console.log(error, freeError);

But the output is an empty object {}. I'm expecting the freeError have at least a message property, but there is none.

Is this a part of JavaScript feature or is there something wrong with my code or engine?

I know a way to fix this, but it requires an extra work {...error, message: error.message}. So, yeah, all I need is a clarification so that I can be sure that I am not missing something. Thank you.

connexo
  • 53,704
  • 14
  • 91
  • 128
SnekNOTSnake
  • 1,157
  • 12
  • 24

3 Answers3

20

Object spread only copies enumerable own properties, and at least in some environments, the message is not an enumerable own property.

In Chrome, it's a non-enumerable own property, and in Firefox, it's a property of Error.prototype:

const error = new Error('Error test');

// Chrome logs an object (including "enumerable": false,)
console.log(Object.getOwnPropertyDescriptor(error, 'message'));

// Firefox logs an object (including "enumerable": false,)
console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(error), 'message'));

It's implementation-dependent. I'd manually extract all properties you need:

const error = new Error('Error test');
const { message, stack } = error;
const freeError = { message, stack };
console.log(freeError);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
3

First off, please note that what you are doing is not destructuring - it is called object spread.

Spreading objects only takes ownPropertys into account. Error instances don't have any non-inherited properties. That is why console.log(error) also outputs {}:

const error = new Error('Error test');

const freeError = {...error};
console.log(error, freeError);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Properties

Because inherited properties are not part of the spread result object, error does have a message property (inherited from its prototype), whereas freeError does not have it.

Check this example:

const str = new String('Hello world');

const freeStr = { ...str };

console.log(str.length); // 11
console.log(freeStr.length); // undefined

As you can see str does have a length property (inherited from the String prototype), whereas freeStr does not have it (for the same reason as in your example).

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_instances

Again, see MDN here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_instances

connexo
  • 53,704
  • 14
  • 91
  • 128
1
const freeError = {...error};   

is similar to

const freeError = Object.assign({}, error);

If you want to get the properties,

const freeError = Object.assign({message: error.message}, error);
Tinu Jos K
  • 888
  • 1
  • 8
  • 21