GGizmos
GGizmos

Reputation: 3773

Using proxy as object.property watcher in TypeScript

I have written a sorted map kind of object (SortedMap) which stores objects which implements this MapItem interface.

export interface MapItem {
    id: string;
    sort: number;
    index: number;
}

I'd like for the SortedMap to resort its collections when somebody changes the sort property of one of the MapItems in its internal store, so I am trying to trigger a resort when I see that the sort changes. When a new item is added to the collection I wanted to add some kind of "watcher" that looks for changes in any of the collection MapItem.sort properties.

I thought I could do this with proxies following the pattern described on MDN Proxy, so wrote this function that is called when a new item is added to SortedMap

    private addSortChangeHandler(item: MapItem) {
        let self = this;
        let watcher = {
            set(obj: MapItem, prop: string, value: number | string) {
                switch (prop) {
                    case "sort":
                        if (value <= 0) {
                            obj.sort = -1
                        } else {
                            obj.sort = <number>value;
                        }
                        self.sortIndex();
                        break;
                    case "index":
                        obj.index = <number>value;
                        break;
                    case "id":
                        obj.id = <string>value;
                        break;
                }
            }
        }
        let proxy = new Proxy(item, watcher);
        this._watcher.push(proxy);
    }

However the compiler has a long list of complaints with the value watcher in the statement let proxy = new Proxy(item, watcher). Not sure how to resolve this. The documentation of Proxy is almost non-existent in the TypeScript documentation itself.

Once I get that problem solved, is it correct that I need to save these Proxy objects somewhere (in this._watchers array in the code above) so long as the object is in the sorted Map or they will be garbage collected? Or are they bound somehow to the object to which they are attached?

Upvotes: 0

Views: 620

Answers (1)

GGizmos
GGizmos

Reputation: 3773

Ok, i stumbled through it. In case anybody is looking to implement similar:

    private addSortChangeHandler(item: MapItem): MapItem {
        let self = this;
        let watcher = <ProxyHandler<MapItem>>{}
        watcher.set = function (target, p, value, receiver) {
            switch (p) {
                case "sort":
                    if (self._sorting) {
                        target.sort = <number>value;  //a new item is being added

                    } else {  //the item is already in the colleciton
                        if (value <= 0) {
                            target.sort = -1
                        } else {
                            target.sort = <number>value;
                        }
                        self.sortIndex();
                    }
                    break;
                case "index":
                    target.index = <number>value;
                    break;
                case "id":
                    target.id = <string>value;
                    break;
            }
            return true;
        }
        let proxy = new Proxy(item, watcher);
        return proxy;
    }

A couple of things I learned, not immediately obvious.

The object returned by new Proxy(item, watcher)is not of "Proxy" type (apparently no such thing)but rather of the type attribute specified when creating the ProxyHandler in this case, MapItem. But now it has been endowed with these new capabilities defined in the handler, like in this case the ability to intercept 'set' operations and do stuff.

Upvotes: 1

Related Questions