When calling toString() or coercing into a string an object that doesn’t implement its own toString method, it returns [object Object] which is often not what was intended.

Why is this an issue?

When using an object in a string context, a developer wants to get the string representation of the state of an object, so obtaining [object Object] is probably not the intended behaviour and might even denote a bug.

How to fix it

You can simply define a toString() method for the object or class.

Code examples

Noncompliant code example

class Foo {};
const foo = new Foo();

foo + ''; // Noncompliant - evaluates to "[object Object]"
`Foo: ${foo}`; // Noncompliant - evaluates to "Foo: [object Object]"
foo.toString(); // Noncompliant - evaluates to "[object Object]"

Compliant solution

class Foo {
  toString() {
    return 'Foo';
  }
}
const foo = new Foo();

foo + '';
`Foo: ${foo}`;
foo.toString();

Noncompliant code example

const foo = {};
foo + ''; // Noncompliant - evaluates to "[object Object]"
`Foo: ${foo}`; // Noncompliant - evaluates to "Foo: [object Object]"
foo.toString(); // Noncompliant - evaluates to "[object Object]"

Compliant solution

const foo = {
  toString: () => {
    return 'Foo';
  }
}
foo + '';
`Foo: ${foo}`;
foo.toString();

Exceptions

This rule does not raise an issue when a direct toString() call is the first statement in a branch that checks the same object against Object.prototype.toString.

function render(value) {
  if (value.toString !== Object.prototype.toString) {
    return value.toString();
  }

  return undefined;
}

function renderOrFallback(value, fallback) {
  if (value.toString === Object.prototype.toString) {
    return fallback;
  } else {
    return value.toString();
  }
}

This rule also does not raise an issue when the result of a direct toString() call is stored in a constant, immediately checked against [object Object], and only the non-default result is used. The same applies when the default result is handled in the if branch and the validated value is used in else.

function pretty(data) {
  if (data && typeof data === 'object' && typeof data.toString === 'function') {
    const rendered = data.toString();
    if (rendered !== '[object Object]') {
      return rendered;
    }
  }

  return data;
}

This rule also does not raise an issue when a value is used in a string context inside a branch where typeof checks prove that the value cannot be an object. This includes branches that accept only primitive values and else branches reached after handling the object case.

function renderValue(value) {
  if (
    typeof value === 'string' ||
    typeof value === 'number' ||
    typeof value === 'bigint'
  ) {
    return 'value=' + value;
  }

  return undefined;
}

function renderFallback(value) {
  if (typeof value === 'object') {
    return '';
  } else {
    return `Unexpected value: ${value}`;
  }
}

Resources

Documentation