# Interpolating objects in error messages (e.g. like console.error)

**URL:** <https://es.discourse.group/t/interpolating-objects-in-error-messages-e-g-like-console-error/822>\
**Category:** 💡 Ideas\
**Created:** [June 18, 2021, 12:08am UTC](https://es.discourse.group/t/interpolating-objects-in-error-messages-e-g-like-console-error/822 "2021-06-18T00:08:35Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jamesernator](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jamesernator/32/538_2.png) [@Jamesernator](https://es.discourse.group/u/Jamesernator)\
**Post date:** [June 18, 2021, 12:08am UTC](https://es.discourse.group/t/interpolating-objects-in-error-messages-e-g-like-console-error/822/1 "2021-06-18T00:08:35Z")

</div>

Currently when creating custom errors it is quite difficult to insert other data, for example consider a trivial example of a simple assertion function that checks if it's value is a string:

```javascript
function assertIsString(value) {
  if (typeof value !== "string") {
    throw new TypeError(`Value was not a string`);
  }
}

assertIsString({ x: 10, y: 20 });

```

This is fairly weak error message though, upon seeing the message "Value was not a string" little information is provided as to what was not a string.

Now we can try to interpolate values into our error message e.g.:

```javascript
throw new TypeError(`${ value } was not a string`);

```

But as expected, the default stringification for most objects is just `[object Object]`, not particularly useful. One could use `JSON.stringify` but this again only works on objects that are valid JSON and will break completely in the precense of object cycles.

Now a number of host environments already support interpolating objects into messages via `console.error`.

For example in Node for the following code we get a nicely formatted string:

```javascript
const o = { x: 10, y: 20 };
console.error(`%o was not a string`, o)

```

```javascript
{ x: 10, y: 20 } was not a string

```

In Chrome Devtools this is even better, as not only does it pretty print the object, but it is expandable and explorable as an object:

![image](https://global.discourse-cdn.com/free1/uploads/es/original/1X/46f85ba9d134dc963a0628ce971b616691594f2a.png)

It would be cool if error messages supported something similar, so that when an error is shown it has nicely formatted and explorable objects.

Now there's a couple ways this could be done, either we adopt the [console specifcation's formatter syntax](https://console.spec.whatwg.org/#formatter), i.e. we would do something like:

```javascript
class Error {
  constructor(message: string, ...data: any[]) {
    const stackMessage = HostFormatMessage(message, data);
    // etc
  }
}

throw new Error(`Expected %o to be a string`, value);

```

Or perhaps a more generic mechanism for a "formatted" message:

```javascript
class Message {
  static create(strings: TemplateStringsArray, ...data: any[]): Message {
    return new Message(parts, data);
  }

  #strings: TemplateStringsArray;
  #data: any[];
  
  constructor(strings: TemplateStringsArray, data: any[]) {
    this.#strings = strings;
    this.#data = data;
  }

  toString(): string {
    return HostFormatMessage(this.#string, this.#data);
  }
}

throw new Error(Message.create`Expected ${ o } to be a string`);
// Could even work with other APIs e.g. all the console methods, in a cross-platform way:
console.log(Message.create(`Saw value ${ o }, adding to processing queue`));

```

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [June 18, 2021, 2:04am UTC](https://es.discourse.group/t/interpolating-objects-in-error-messages-e-g-like-console-error/822/2 "2021-06-18T02:04:22Z")

</div>

I'll note that in Node, if you attach properties to the error object, they'll show up when the error is thrown. This doesn't seem to be the case in Chrome though, not sure about other browsers.

```javascript
> const myError = new Error('Value was not a string')
undefined
> myError.value = { x: 10, y: 20 }
{ x: 10, y: 20 }
> throw myError
Uncaught Error: Value was not a string
    at REPL9:1:17
    at Script.runInThisContext (vm.js:133:18)
    ...
    at REPLServer.Interface._line (readline.js:666:8) {
  value: { x: 10, y: 20 }
}

```

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [June 18, 2021, 8:03am UTC](https://es.discourse.group/t/interpolating-objects-in-error-messages-e-g-like-console-error/822/3 "2021-06-18T08:03:20Z")

</div>

Perhaps the Error cause proposal could help with that particular example?

> **[tc39/proposal-error-cause](https://github.com/tc39/proposal-error-cause)**
>
> TC39 proposal for accumulating errors. Contribute to tc39/proposal-error-cause development by creating an account on GitHub.

```javascript
throw new Error('Value was not a string', { cause: value })

```

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [June 18, 2021, 10:49pm UTC](https://es.discourse.group/t/interpolating-objects-in-error-messages-e-g-like-console-error/822/4 "2021-06-18T22:49:21Z")

</div>

I'll note that Node supports a very, _very_ small superset of the console spec for its [`util.format`](https://nodejs.org/api/util.html#util_util_format_format_args). The only differences it has with when a format string is passed is this:

- `%%` gets reduced to a single `%` without consuming any arguments. (It's odd the console spec doesn't account for this.)
- `%j` results in the object displayed as JSON (as if via `JSON.stringify`, but with circular references replaced with the string `"[Circular]"`).
- `%c` is ignored.
