Harness-engineering js-proxy-pattern

JS Proxy Pattern

install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/js-proxy-pattern" ~/.claude/skills/intense-visions-harness-engineering-js-proxy-pattern && rm -rf "$T"
manifest: agents/skills/claude-code/js-proxy-pattern/SKILL.md
source content

JS Proxy Pattern

Intercept and control object property access with ES6 Proxy

When to Use

  • You need to validate, log, or transform property reads/writes without changing the target object
  • Implementing reactive data systems (watching object mutations)
  • Adding access control or lazy initialization to expensive objects
  • Building observable models for state management

Instructions

  1. Create a handler object with trap methods (
    get
    ,
    set
    ,
    deleteProperty
    , etc.).
  2. Wrap the target object:
    const proxy = new Proxy(target, handler)
    .
  3. In
    set
    traps, always call
    Reflect.set(target, prop, value)
    to apply the change and return its boolean result.
  4. In
    get
    traps, use
    Reflect.get(target, prop, receiver)
    to preserve prototype chain behavior.
  5. Use
    Reflect
    methods in traps — they mirror the Proxy trap API and ensure correct semantics.
const validator = {
  set(target, prop, value) {
    if (prop === 'age') {
      if (typeof value !== 'number' || value < 0) {
        throw new TypeError('Age must be a non-negative number');
      }
    }
    return Reflect.set(target, prop, value);
  },
};

const person = new Proxy({}, validator);
person.age = 30; // OK
person.age = -1; // Throws TypeError
  1. Avoid deeply nested Proxy wrapping — it compounds performance overhead on every property access.

Details

ES6

Proxy
gives you a meta-programming hook at the object level. Traps intercept fundamental operations: get, set, has, deleteProperty, apply (for functions), and construct (for classes).

Trade-offs:

  • Proxy adds overhead per property access — avoid on hot paths (tight loops, rendering cycles)
  • Proxied objects are not equal to their targets (
    proxy !== target
    ) — equality checks must use the target
  • Proxies are not serializable —
    JSON.stringify(proxy)
    serializes the underlying target, which may surprise callers
  • Debugging is harder — the DevTools shows the proxy wrapper, not the target directly

When NOT to use:

  • For simple validation — just write a setter method or use a class
  • For immutability at scale —
    Object.freeze()
    is simpler and has no runtime overhead per access
  • When you need ES5 compatibility — Proxy cannot be polyfilled

Related patterns:

  • Observer Pattern — Proxy can power reactive observation of object mutations
  • Singleton Pattern — a Proxy can wrap a singleton to control access

Source

https://patterns.dev/javascript/proxy-pattern

Process

  1. Read the instructions and examples in this document.
  2. Apply the patterns to your implementation, adapting to your specific context.
  3. Verify your implementation against the details and edge cases listed above.

Harness Integration

  • Type: knowledge — this skill is a reference document, not a procedural workflow.
  • No tools or state — consumed as context by other skills and agents.

Success Criteria

  • The patterns described in this document are applied correctly in the implementation.
  • Edge cases and anti-patterns listed in this document are avoided.