JS Define getter for every property of a class

I’m currently trying to write a class that defines a generic getter and setter for all properties of the object. The closest thing I have right now is functions named get and set for the class as a whole which takes a property name and returns it if it exists.

I’ve tried to use the computed property names option for dynamically defining a getter, but I’m getting errors on either giving the getter arguments, or errors about prop being undefined. Is there any way to define a pair that works for both obj.prop and obj['prop'] that doesn’t require writing them for every property in a class?

Current code for reference:

class Holder {
    constructor(def="the door"){
    this.holds=def
  }
  // Generic getter for every possible property
  get (prop) {
    if(prop in this){
        return this[prop];
    } else {
        return `No property found named '${prop}'`;
    }
  }
  // Generic setter, performs magic that sets `changed` as well.
  set (prop, value) {
        if(prop in this){
        this[prop] = value;
        this.changed = true;
    }
  }
}

const hodor = new Holder();
console.log(hodor.holds); // Expected: "the door"
console.log(hodor.derp); // Expected: "No property found named 'derp'"

Answer

So if you run the code above you’ll find it’s not actually working. The console.log(hodor.holds) is going directly to the underlying this.holds instance property.

A quick search on StackOverflow led me to this Is it possible to implement dynamic getters/setters in JavaScript?. I’ve modified your code to use this Proxy approach and this now works correctly:

class Holder {
    constructor(def = 'the door') {
        this.holds = def;

        return new Proxy(this, {
            get(target, name, receiver) {
                if (name in target) {
                    return target[name];
                } else {
                    return `No property found named '${name}'`;
                }
            },
            set(target, name, receiver) {
                if (name in target) {
                    target[name] = receiver;
                    target.changed = true;
                }
            },
        });
    }
}

const hodor = new Holder();
console.log(hodor.holds); // Logs: the door
console.log(hodor.derp); // Logs: "No property found named 'derp'"
hodor.holds = 'bar';
console.log(hodor.holds); // Logs "bar"