Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create dynamic non-configurable properties using Proxy

I want to create dynamic non-configurable properties using Proxy. I tried this:

const proxy = new Proxy({}, {
  getOwnPropertyDescriptor() {
    return {
      configurable: false,
      enumerable: false,
    };
  },
});

console.log(Reflect.getOwnPropertyDescriptor(proxy, 'test'));

But I'm getting an error:

TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'test' which is either non-existant or configurable in the proxy target

MDN says that:

A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.

But it doesn't explain what's the reasoning behind this.

Is there any workaround for this error?

like image 202
Michał Perłakowski Avatar asked Dec 30 '25 21:12

Michał Perłakowski


2 Answers

Not really. This is due to the desirable invariant that, if you observe a non-configurable property in an object, it can't magically disappear. And if it's also non-writable, its value must not change.

If you couldn't rely on this, getOwnPropertyDescriptor would be basically useless.

Enforcing you not to use non-configurable properties, or defining them in the target, implies that you won't violate this invariant, because the invariant holds on the target by construction. That is, ECMAScript doesn't allow you to use the Proxy customizations in a way that breaks these invariants.

Some of the internal method invariants defined in 6.1.7.3 are essential integrity invariants. These invariants are explicitly enforced by the proxy object internal methods specified in this section. An ECMAScript implementation must be robust in the presence of all possible invariant violations.

So either report the property as configurable, or define non-configurable properties in the target.

If you want dynamic properties I recommend to just lie say the property is configurable. And then add a defineProperty trap which returns false, effectively preventing redefinitions.

like image 92
Oriol Avatar answered Jan 01 '26 09:01

Oriol


It seems that if inside getOwnPropertyDescriptor trap I define that property on the target object before returning the descriptor, it works fine.

const proxy = new Proxy({}, {
  getOwnPropertyDescriptor(target, property) {
    const descriptor = {
      configurable: false,
      enumerable: false,
    };
    Reflect.defineProperty(target, property, descriptor);
    return descriptor;
  },
});

console.log(Reflect.getOwnPropertyDescriptor(proxy, 'test'));

The side effect is (obviously) the created property, which cannot be deleted (because it's non-configurable), which means that for example I cannot report it as non-existent later, but in my case it doesn't matter.

like image 39
Michał Perłakowski Avatar answered Jan 01 '26 09:01

Michał Perłakowski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!