How to extend console.log which can accept args without using additional ()?

Viewed 532

I've been working on extending console.log to make a colorful one that keeps the stack trace as to where it has been called. I've tried some solutions, but finally reach this point:

const colorizedLog = (text, color= "#40a7e3", ...args) =>
  console.log.bind(
    console,
    `%c ${text}`,
    `font-weight:bold; color:${color}`,
    ...args
  );
colorizedLog("Title:", "#40a7e3", "This is a working example")();

With this little binding, we will be able to keep the stack trace, but the problem here is we have to use it with an annoying extra () at the end, because of returning value is the function itself which is the result of bind:

 colorizedLog(
    "Title:",
    "info",
    "This is a working example")();

The top other resources that I've read through are as below:

  1. Extending console.log
  2. Macro using babel- kent.c dodds
  3. Webpack Define plugin

Check Stack trace

// useAppVersion.ts

export enum ColorStatus {
  info = "#40a7e3",
  ServerInfo = "#3e618a",
  warning = "#f28021",
  danger = "#b41e4a",
  dark = "#222222",
}
export const colorizedLog = (
  text: string,
  status: keyof typeof ColorStatus = "dark",
  ...args: any
) =>
  console.log.bind(
    console,
    `%c ${text}`,
    `font-weight:bold; color: ${ColorStatus[status]}`,
    ...args
  );

export const colorizedLog2 = (...args: any) => colorizedLog(...args)();
// log.ts
console.log("console.log:", "Text");
colorizedLog("colorizedLog:", "dark", "Text")();
colorizedLog2("colorizedLog2:", "dark", "Text");

Chrome Console

As You can see the last one's stack trace is not correct or what we want. How to make it work? enter image description here

2 Answers

You can make it immediately invoked:

const colorizedLog = (text, color= "#40a7e3", ...args) =>
  console.log.bind(
    console,
    `%c ${text}`,
    `font-weight:bold; color:${color}`,
    ...args
  )();

colorizedLog("Title:", "#40a7e3", "This is a working example");

If you don't mind adding another call to that stack trace, you can wrap it in another function that hides the extra ():

const rawColorizedLog = (
  text: string,
  status: keyof typeof ColorStatus = "dark",
  ...args: any
) =>
  console.log.bind(
    console,
    `%c ${text}`,
    `font-weight:bold; color: ${ColorStatus[status]}`,
    ...args
  );
export const colorizedLog = (...args: any) => rawColorizedLog(...args)();

Then you can just call colorizedLog(...whatever) but you will have an extra call to rawColorizedLog in the stack, but I'm sure you can think of a clever name for rawColorizedLog to cover up the extra call with something cooler ;)

Related