Property changed decorator using ES7

Watching a model for changes is a pretty common requirement, and you often end up with code like this (in ES6):

export default class Foo extends EventEmitter {
    get bar() {
        return this._bar;
    }

    set bar(value) {
        if (value !== this._bar) {
            this._bar = value;
            this.emit("barChanged");
        }
    }
}

Boilerplate code is always an excuse for metaprogramming! And this seemed like an ideal use case for the proposed ES7 decorators.

We’re using babeljs via babelify, so needed to enable decorators in our gulpfile:

return browserify({
    ...
    transform: [babelify.configure({
        optional: ["es7.decorators"]
    })],
    ...
});

Once enabled, you can add the decorator:

export default class Foo extends EventEmitter {
    @propertyChanged
    get bar() {
        return this._bar;
    }

    set bar(value) {
        this._bar = value;
    }
}

function propertyChanged(target, name, descriptor) {
    let getter = descriptor.get, setter = descriptor.set;

    descriptor.set = function(value) {
        if (value !== getter.call(this)) {
            setter.call(this, value);
            this.emit(name + "Changed");
        }
    };

    return descriptor;
}