Home > Enterprise >  Print getters when and object is printed in typescript
Print getters when and object is printed in typescript

Time:12-15

Is there an option in TypeScript/JavaScript to print an object who has private properties using their getters instead of printing the private properties names.

By example I have this class in TypeScript

class Vehicle {

  constructor(private _brand: string, private _year: number) {}

  get brand(): string {
    return this._brand;
  }

  get year(): number {
    return this._year;
  }

  set year(year: number) {
    this._year = year;
  }

  set brand(brand: string) {
    this._brand = brand;
  }
}

const vehicle: Vehicle = new Vehicle('Toyota', 10);

console.log(vehicle);

I got this

[LOG]: Vehicle: {
  "_brand": "Toyota",
  "_year": 10
} 

But I'm wondering if I can get something like this

[LOG]: Vehicle: {
  "brand": "Toyota",
  "year": 10
} 

CodePudding user response:

What console.log does varies by environment. If you want to do what you're describing, you'd have to write your own logger function instead, for instance (in JavaScript, but types are fairly easily added) see comments:

function log(obj) {
    // Get the names of getter properties defined on the prototype
    const ctor = obj.constructor;
    const proto = ctor?.prototype;
    const names = new Set(
        proto
            ? Object.entries(Object.getOwnPropertyDescriptors(proto))
                .filter(([_, {get}]) => !!get)
                .map(([name]) => name)
            : []
    );
    // Add in the names of "own" properties that don't start with "_"
    for (const name of Object.keys(obj)) {
        if (!name.startsWith("_")) {
            names.add(name);
        }
    }
    // Create a simple object with the values of those properties
    const simple = {};
    for (const name of names) {
        simple[name] = obj[name];
    }
    // See if we can get a "constructor" name for it, apply it if so
    let objName =
        obj[Symbol.toStringTag]
        || ctor?.name;
    if (objName) {
        simple[Symbol.toStringTag] = objName;
    }
    // Log it
    console.log(simple);
}

Live Example:

"use strict";

function log(obj) {
    // Get the names of getter properties defined on the prototype
    const ctor = obj.constructor;
    const proto = ctor?.prototype;
    const names = new Set(
        proto
            ? Object.entries(Object.getOwnPropertyDescriptors(proto))
                .filter(([_, {get}]) => !!get)
                .map(([name]) => name)
            : []
    );
    // Add in the names of "own" properties that don't start with "_"
    for (const name of Object.keys(obj)) {
        if (!name.startsWith("_")) {
            names.add(name);
        }
    }
    // Create a simple object with the values of those properties
    const simple = {};
    for (const name of names) {
        simple[name] = obj[name];
    }
    // See if we can get a "constructor" name for it, apply it if so
    let objName =
        obj[Symbol.toStringTag]
        || ctor?.name;
    if (objName) {
        simple[Symbol.toStringTag] = objName;
    }
    // Log it
    console.log(simple);
}

class Vehicle {
    constructor(_brand, _year) {
        this._brand = _brand;
        this._year = _year;
    }
    get brand() {
        return this._brand;
    }
    get year() {
        return this._year;
    }
    set year(year) {
        this._year = year;
    }
    set brand(brand) {
        this._brand = brand;
    }
}
const vehicle = new Vehicle('Toyota', 10);
log(vehicle);

Lots of room to tweak that how you like it, that's just a sketch of how you might go about it.

CodePudding user response:

I don't think there is a way to do that, but you could create a log method in the class, like this:

  log() {
    console.log({
      brand: this.brand,
      year: this.year,
    });
  }

And then simply call vehicle.log();

You'd then get a log like this {brand: 'Toyota', year: 10}

  • Related