TypeScript toString ignored by debugger TypeScript toString ignored by debugger typescript typescript

TypeScript toString ignored by debugger


So your question is almost similar to below

How to change string representation of objects in Nodejs debug console view

The toString behaviour is not there as a part of normal v8 engine debugger API.

I had dived in deep for the link I posted earlier and found few interesting pointers

  • Compiling NodeJS from source and watching the debugger traffic, I realised there is a customFormatter concept

    setCustomObjectFormatterEnabled: function(enabled)

  • I was able to change some stuff in this JavaScript and send the evaluated toString values back with the v8 API call

  • The default VS code needs to be modified to change the behaviour and show a different text.

  • I never got a clean way to actually see what can be done and how to formulate a proper solution, so left it there itself.

So in short it is possible, but requires a decent effort to get it working


Can you provide an example what what you actually want to see at which place in the debugger?

If the question is about the variable scope (ie. Local and global variables available), the debugger will not call toString() as it would actually execute code within the debugged script which in turn may modify the state. Imagine an endless loop in toString().


I found out how to do it in Chrome DevTools (still don't have a solution for VSCode):

custom string in dev tools

For this to work we need to enable custom formatters in dev tools:

  • Open dev tools
  • Click on the hamburger menu (the 3 vertical dots) on the top right
  • Click on "settings"
  • Under "Console", make sure "Enable custom formatters" is checked.

With this done you can create a custom formatter in the code and then assign it to window["devtoolsFormatters"].

The full code for my example is here:

class Person {    constructor(firstName, lastName) {        this.firstName = firstName;        this.lastName = lastName;    }    toString() {        return `${this.firstName} ${this.lastName}`;    }}Formatter = function (simpleFormatter) {    this._simpleFormatter = simpleFormatter;}Formatter.prototype = {    header: function (object) {        if ((object instanceof Node))            return null;        var header = new JsonMLElement("span");        let title = this._simpleFormatter.description(object);        if (typeof object.toString !== "undefined") {            title = `${object.toString()} [${this._simpleFormatter.description(object)}]`;        }        header.createTextChild(title);        return header.toJsonML();    },    hasBody: function (object) {        if (object instanceof Array)            return false;        return this._simpleFormatter.hasChildren(object);    },    body: function (object) {        var body = new JsonMLElement("ol");        body.setStyle("list-style-type:none; padding-left: 0px; margin-top: 0px; margin-bottom: 0px; margin-left: 12px");        var children = this._simpleFormatter.children(object);        for (var i = 0; i < children.length; ++i) {            var child = children[i];            var li = body.createChild("li");            var objectTag;            if (typeof child.value === "object")                objectTag = li.createObjectTag(child.value);            else                objectTag = li.createChild("span");            var nameSpan = objectTag.createChild("span");            nameSpan.createTextChild(child.key + ": ");            nameSpan.setStyle("color: rgb(136, 19, 145);");            if (child.value instanceof Node) {                var node = child.value;                objectTag.createTextChild(node.nodeName.toLowerCase());                if (node.id)                    objectTag.createTextChild("#" + node.id)                else                    objectTag.createTextChild("." + node.className)            }            if (typeof child.value !== "object")                objectTag.createTextChild("" + child.value);        }        return body.toJsonML();    },    _arrayFormatter: function (array) {        var j = new JsonMLElement();        j.createTextChild("[");        for (var i = 0; i < array.length; ++i) {            if (i != 0)                j.createTextChild(", ")            j.createObjectTag(array[i]);        }        j.createTextChild("]");        return j;    }}JsonMLElement = function (tagName) {    this._attributes = {};    this._jsonML = [tagName, this._attributes];}JsonMLElement.prototype = {    createChild: function (tagName) {        var c = new JsonMLElement(tagName);        this._jsonML.push(c.toJsonML());        return c;    },    createObjectTag: function (object) {        var tag = this.createChild("object");        tag.addAttribute("object", object);        return tag;    },    setStyle: function (style) {        this._attributes["style"] = style;    },    addAttribute: function (key, value) {        this._attributes[key] = value;    },    createTextChild: function (text) {        this._jsonML.push(text + "");    },    toJsonML: function () {        return this._jsonML;    }}function SimpleFormatter() {}SimpleFormatter.prototype = {    description: function (object) {        if ((typeof object === "object") && object)            return object.constructor.name;        return object;    },    hasChildren: function (object) {        return (typeof object === "object");    },    children: function (object) {        var result = [];        for (var key in object)            result.push({ key: key, value: object[key] });        return result;    }}window["devtoolsFormatters"] = [new Formatter(new SimpleFormatter())];const p = new Person("Luke", "Skywalker")console.log(p)

More details can be found in this link (my code is just a slightly modified version of one of the examples posted in that article).