Proxy Pattern in TypeScript

Imagine you've implemented a feature using a third-party library installed via npm, but you find certain aspects of its behavior or provided APIs unsatisfactorily. Without direct access to the library's source code, the Proxy pattern becomes a valuable tool.

By employing the Proxy pattern, you can intercept and modify the library's behavior, introduce additional mechanisms, and seamlessly adapt the functionality to meet your specific requirements. This allows for a flexible and non-intrusive approach to customizing third-party libraries in your projects.

Definition

The Proxy pattern is a structural design pattern that acts as a surrogate or placeholder for another object, controlling access to it. This intermediary, known as the proxy, allows developers to add, modify, or restrict functionality without directly modifying the core behavior of the target object.

The Proxy pattern is commonly used to implement scenarios such as lazy loading, access control, logging, and validation, providing a flexible way to enhance the interactions with the underlying objects. It promotes encapsulation, security, and customization in software systems.

Custom Proxy

class RealTarget {
  operation() {
    console.log("RealTarget: Performing operation.");
  }
}
class ProxyAdapter {
  operation() {
    console.log("ProxyAdapter: Logging before operation.");
    new RealTarget().operation();
    console.log("ProxyAdapter: Logging after operation.");
  }
}
// Calling it
const realTarget = new ProxyAdapter();
realTarget.operation();
// The result will be 3x console.logs

Native JavaScript Proxy

class RealTarget {
  operation() {
    console.log("RealTarget: Performing operation.");
  }
}
const proxyHandler = {
  apply: function (target, thisArg, args) {
    console.log("JS Proxy: Logging before operation.");
    const result = target.operation.apply(thisArg, args);
    console.log("JS Proxy: Logging after operation.");
    return result;
  },
};
const proxy = new Proxy(new RealTarget(), proxyHandler);
// Calling it
proxy.operation();
// The result will be 3x console.logs

Benefits

Controlled Access

Proxies manage access to target objects, imposing restrictions or conditions on operations.

Enhanced Security

Encapsulating access logic in proxies improves application security.

Lazy Loading

Proxies enable lazy loading, deferring object creation until necessary.

Logging and Monitoring

Proxies facilitate runtime monitoring and logging of object interactions.

Validation and Adaptation

Proxies validate input, adapt data formats, or implement custom logic without modifying the original object.

Conclusion

The Proxy pattern in TypeScript provides a concise and powerful mechanism for adding control and customization to object interactions. Whether through custom adapters or the built-in JS Proxy, it addresses access control, validation, and logging, enabling the creation of flexible and maintainable systems.