user6440264
user6440264

Reputation:

Extending method by ES6 Proxy works but with TypeError

Implementing a function to extend object method by ES6 Proxy works but with TypeError as below:

const extendMethod = (obj) => (key) => (f) => {
    const handler = {
        get: (target, propKey, receiver) => {
            const targetValue = Reflect.get(target, propKey, receiver);
            return key === propKey
                ? f(target.valueOf())
                : (typeof targetValue === "function")
                    ? (...args) => Object(target.valueOf())[propKey](...args)
                    : targetValue;
        }
    };
    return new Proxy(obj, handler);
};

const a = { x: 5 };
const f = (target) => { console.log(target); };
const a1 = extendMethod(a)("log")(f);
a1.log(); //{x:5}
//TypeError: a1.log is not a function

How to modify the code to avoid the error? thanks.

Upvotes: 0

Views: 57

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370809

The script is expecting a1.log to evaluate to a function because it proceeds to get called as a1.log();. But with the line

? f(target.valueOf())

, the f function is run, and the output of calling f is then returned to the outside. But the output of f is undefined, because the (outer) f doesn't return anything.

One way to suppress the error would be to return a function that doesn't do anything:

? (f(target.valueOf()), () => void 0)

const extendMethod = (obj) => (key) => (f) => {
    const handler = {
        get: (target, propKey, receiver) => {
            const targetValue = Reflect.get(target, propKey, receiver);
            return key === propKey
                ? (f(target.valueOf()), () => void 0)
                : (typeof targetValue === "function")
                    ? (...args) => Object(target.valueOf())[propKey](...args)
                    : targetValue;
        }
    };
    return new Proxy(obj, handler);
};

const a = { x: 5 };
const f = (target) => { console.log(target); };
const a1 = extendMethod(a)("log")(f);
a1.log(); //{x:5}

Or you might simply access the a1.log property (calling the function as a side effect) and not invoke it:

const extendMethod = (obj) => (key) => (f) => {
    const handler = {
        get: (target, propKey, receiver) => {
            const targetValue = Reflect.get(target, propKey, receiver);
            return key === propKey
                ? f(target.valueOf())
                : (typeof targetValue === "function")
                    ? (...args) => Object(target.valueOf())[propKey](...args)
                    : targetValue;
        }
    };
    return new Proxy(obj, handler);
};

const a = { x: 5 };
const f = (target) => { console.log(target); };
const a1 = extendMethod(a)("log")(f);
a1.log; //{x:5}

If the outer f function did return a function (that is, if it was a higher-order function), then you would be able to use a1.log() normally:

const extendMethod = (obj) => (key) => (f) => {
    const handler = {
        get: (target, propKey, receiver) => {
            const targetValue = Reflect.get(target, propKey, receiver);
            return key === propKey
                ? f(target.valueOf())
                : (typeof targetValue === "function")
                    ? (...args) => Object(target.valueOf())[propKey](...args)
                    : targetValue;
        }
    };
    return new Proxy(obj, handler);
};

const a = { x: 5 };
const f = (target) => {
  console.log(target);
  return arg => {
    console.log('inner fn! ' + arg);
  };
};
const a1 = extendMethod(a)("log")(f);
a1.log('foo');

Upvotes: 2

Related Questions