Proxy & Reflect API
debt(d7/e5/b6/t8)
Closest to 'only careful code review or runtime testing' (d7). ESLint and TypeScript can flag *missing* Reflect usage or obvious Proxy misconfigurations, but the detection_hints explicitly state 'automated: no'. Silent infinite loops, incorrect 'this' binding, and subtle trap-firing side effects require runtime observation or deep code review to catch.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes using Proxy + Reflect for transparent interception, which requires identifying all property-access points, updating traps (Reflect.get/set/etc.), and potentially refactoring method calls to preserve 'this'. Common mistakes like handling sealed objects or preventing infinite loops are per-proxy fixes, but the pattern shift is non-trivial.
Closest to 'persistent productivity tax' (b6, between b5 and b7). Proxy/Reflect appears in web and cli contexts; once introduced as the reactivity or validation layer (Vue 3, MobX, custom frameworks), every future maintainer must understand metaprogramming traps, trap semantics, and Reflect forwarding. The reach is broad (affects all components using the proxied object), but not architectural rewrite-or-live-with-it (b9) unless it becomes the system's core reactivity model.
Closest to 'serious trap' (t7). The misconception directly contradicts the common belief that Proxy is 'only for experts'—yet Vue 3 uses it transparently. Common_mistakes reveal multiple t7/t8 behaviors: returning false from set traps silently fails in non-strict but throws in strict mode; Proxy traps fire for *every* access (including internal), not just explicit ones; 'this' binding breaks with class instances; sealed/frozen objects throw TypeError. Developers familiar with property getters/setters or simple interception will guess wrong.
Also Known As
TL;DR
Explanation
new Proxy(target, handler) creates a proxy that intercepts operations on the target. The handler object defines traps: get (property access), set (property assignment), has (in operator), apply (function call), construct (new operator). Reflect provides corresponding static methods (Reflect.get, Reflect.set) that mirror the trapped operations, useful for forwarding in handlers. Proxy powers Vue 3's reactivity system, validation libraries, and mock frameworks.
Common Misconception
Why It Matters
Common Mistakes
- Not using Reflect.set/Reflect.get inside traps — returning false from a set trap triggers a TypeError in strict mode.
- Proxying sealed or frozen objects — throws TypeError since the proxy cannot intercept property changes.
- Not considering that Proxy traps fire for every access, including internal operations — can cause infinite loops if not careful.
- Proxying class instances without handling 'this' — some methods break if 'this' is not the target, not the proxy.
Code Examples
// Manual validation on every setter — verbose and easy to miss:
class User {
setEmail(email) {
if (!email.includes('@')) throw new Error('Invalid');
this._email = email;
}
setAge(age) {
if (age < 0) throw new Error('Invalid');
this._age = age;
}
// Must remember to add validation to every setter
}
// Proxy — intercept all property assignments:
const validators = { email: v => v.includes('@'), age: v => v >= 0 };
const validated = (obj) => new Proxy(obj, {
set(target, prop, value) {
if (validators[prop] && !validators[prop](value)) {
throw new TypeError(`Invalid value for ${prop}: ${value}`);
}
return Reflect.set(target, prop, value); // Default set behaviour
}
});
const user = validated({});
user.email = 'alice@example.com'; // OK
user.email = 'not-an-email'; // TypeError: Invalid value for email