‘inStock’ is assigned a value but never used no-unused-vars

I am trying to refactor some code and wanted to use destructuring to make the code a bit easier to read. I am passing in an object into the remove() function, however one of the variables is returning:

‘inStock’ is assigned a value but never used no-unused-vars

According to the eslint docs:

‘A read for a modification of itself is not considered as used.’ https://eslint.org/docs/rules/no-unused-vars

I was wondering whether if there’s a way to resolve this issue without:

  • modifying eslint (no-unused-vars) ?
  • adding /* eslint-disable no-unused-vars */ comments inline ?

Thanks in advance

before refactoring:

remove(product) {
  if (product.quantity > 0) {
    product.quantity --;
    product.inStock ++;
  }
}

after refactoring:

remove({ quantity, inStock }) {
  if (quantity > 0) {
    quantity --;
    inStock ++;
  }
}

Answer

Problem

Your refactor is based on the misunderstanding that quantity-- and inStock++ has the same behaviour as product.quantity-- and product.inStock++. The core of this misunderstanding is thinking that the destructured fields still refer to the fields on the object. Let’s take a look at what destructuring really is.

Take this example, with destructuring:

const obj = { foo: 0 };
const { foo } = obj;

Without destructuring, it’d look like this:

const obj = { foo: 0 };
const foo = obj.foo;

The destructuring syntax is just a shortcut of the second example.

What this illustrates is destructuring defines a new variable and assigns the value (not the reference) of the field you’re destructuring to that variable. When you make mutations to that variable, you’ll only mutate the value of the variable but not the value of the object field. Here’s a runnable example, you’ll see that obj.foo hasn’t changed from 0, even though we increment foo which has been destructured from obj:

const obj = { foo: 0 };

var { foo } = obj;

foo++;

console.log(obj); // { "foo": 0 }

Going back to your linting error: the linter is correct, not only raising the fact that the variable is unused but revealing this problem that I’ve explained.

Solution

There are two immediate solutions I can think of:

  1. Don’t destructure. With your example, while destructuring does shorten the amount of code there is, it could introduce confusion as to what is mutated and make the code less understandable – you’ve experienced it yourself.

  2. Reassign the incremented/decremented value back to your object. You’ll need to prefix the operator to the operand because this returns the value after the operation. Postfixing returns the value before the operation (aka the original value).

remove({ quantity, inStock }) {
  if (quantity > 0) {
    product.quantity = --quantity;
    product.inStock = ++inStock;
  }
}

If you ever learn about functional programming, specifically pure functional programming, there might be other patterns you can apply to your scenario but that’s beyond the scope of this answer. These patterns won’t do mutations which could make it easier to understand how data flows through and is changed by your system.