DEV Community

Cover image for Inspect any value without console.log
JSLab
JSLab

Posted on

Inspect any value without console.log

You have a chain. Something in the middle is wrong. You want to see the value between two calls without rewriting the chain into five consts.

Here's the chain we'll poke at:

const orders = [
  { id: 1, total: 120, paid: true },
  { id: 2, total: 80, paid: false },
  { id: 3, total: 45.5, paid: true },
];

const revenue = orders
  .filter((o) => o.paid)
  .map((o) => o.total)
  .reduce((sum, n) => sum + n, 0);
Enter fullscreen mode Exit fullscreen mode

revenue is 165.5. But say it wasn't, and you want to know what .map handed to .reduce.

1. The console.log(x) || x trick

console.log returns undefined, so console.log(x) || x logs x and then evaluates to x. Drop it into any arrow function and the chain keeps working:

const revenue = orders
  .filter((o) => o.paid)
  .map((o) => console.log(o.total) || o.total)
  .reduce((sum, n) => sum + n, 0);
// logs 120, then 45.5
Enter fullscreen mode Exit fullscreen mode

It works everywhere. It also looks like a bug to the next person, so take it out before you commit.

2. A tap helper

If you do this often, give it a name. tap logs a value and passes it through unchanged:

const tap = (label) => (value) => {
  console.log(label, value);
  return value;
};

const revenue = orders
  .filter((o) => o.paid)
  .map(tap("paid order"))
  .map((o) => o.total)
  .reduce((sum, n) => sum + n, 0);
Enter fullscreen mode Exit fullscreen mode

tap shines in promise chains, where each .then gets one value:

fetch("https://api.github.com/zen")
  .then((res) => res.text())
  .then(tap("zen"));
Enter fullscreen mode Exit fullscreen mode

3. Split it and read the pieces

The honest fix is often to name the steps:

const paid = orders.filter((o) => o.paid);
const totals = paid.map((o) => o.total);
const revenue = totals.reduce((sum, n) => sum + n, 0);
Enter fullscreen mode Exit fullscreen mode

Now each step is a line, and you can log any of them. The cost is three console.logs you'll add, read, and delete.

The same thing in a scratchpad

This is the loop that JSLab, a JavaScript & TypeScript scratchpad for macOS, is built around. Two features cover all three cases above.

Auto Log. Every top-level expression is logged beside its line, so a bare name is enough:

const paid = orders.filter((o) => o.paid);
paid;          // logged: the two paid orders
paid.length;   // logged: 2
Enter fullscreen mode Exit fullscreen mode

Assignments, x++ and console.* calls are never auto-logged, so the output stays readable.

Magic comments. End a line with //? and JSLab logs exactly that statement, even inside a function or a loop. /*?*/ works mid-expression, so you can look inside the chain without breaking it:

orders.filter((o) => o.paid) /*?*/ .map((o) => o.total);
Enter fullscreen mode Exit fullscreen mode

That logs the filtered array, before .map runs. And //? $.length logs an expression built from the value, which is $:

const totals = orders.filter((o) => o.paid).map((o) => o.total); //? $.length
Enter fullscreen mode Exit fullscreen mode

That logs 2 instead of the whole array.

Here are all three in one JSLab tab: //? inside a function (line 4), /*?*/ on a loop (line 7), and //? $.length (line 12), which logs 2.

A JSLab tab in TypeScript. Line 4 has //? inside a function, line 7 has /*?*/ on a for…of loop, and line 12 ends with //? $.length. The output lists 9.99, 11.988, 19.5, 23.4, 4.25 and 5.1, tagged with lines 7 and 4, then 3 tagged :11 and 2 tagged :12.

Every row in the output is tagged with the line that produced it, and clicking the line number jumps the editor there. Nothing to remove before you commit: there's no console.log to forget.

Which one when

  • Shipping code, or code someone else reads: split it into named steps.
  • Quick look in a real project: tap, or || x if you promise to delete it.
  • Working something out in a scratchpad: let Auto Log and //? do it.

JSLab launches Nov 15. The docs for Auto Log and magic comments are here: https://js-lab.app/docs/editor

Top comments (0)