Home > Net >  Unable to access private members when redefining method of class
Unable to access private members when redefining method of class

Time:10-10

When defining a private member using #, and then re-defining some member that uses this private member, you will find that you cannot use it anymore:

class Foo {
    #secret = "Keyboard Cat";
    
    method() {
        console.log(this.#secret);
    }
}

const target = Foo.prototype;
const key = "method";

const desc = Object.getOwnPropertyDescriptor(target, key);

const og = desc.value;

desc.value = function (...args) {
    return og.apply(target, args);
};

Object.defineProperty(target, key, desc);

new Foo().method();

Uncaught TypeError: Cannot read private member #secret from an object whose class did not declare it

Why? All I have done is wrap around the original method in this case. Note that this example is a dramatic simplification of using decorators with TypeScript. How could I get around this while still being able to redefine and "change" the method?


Here's the same thing, but with a TypeScript decorator:

const Curse: MethodDecorator = (target, _, desc) => {
    const og = desc.value as Function;

    desc.value = function (...args: any[]) {
        return og.apply(target, args);
    } as any;

    return desc;
};

class Foo {
    #secret = "Keyboard Cat";
    
    @Curse
    method() {
        console.log(this.#secret);
    }
}

new Foo().method();

Playground

CodePudding user response:

The mistake you made is to apply the method to the target, which is Foo.prototype, not to the new Foo instance via the this keyword:

class Foo {
    #secret = "Keyboard Cat";
    
    method() {
        console.log(this.#secret);
    }
}

const target = Foo.prototype;
const key = "method";

const desc = Object.getOwnPropertyDescriptor(target, key);

const orig = desc.value;

desc.value = function (...args) {
    return orig.apply(this, args);
//                    ^^^^
};

Object.defineProperty(target, key, desc);

new Foo().method();

Foo.prototype does not have the #secret private field. You'll get the same error with

class Foo {
    #secret = "Keyboard Cat";
    
    method() {
        console.log(this.#secret);
    }
}

Foo.prototype.method();

  • Related