How to use Proxy objects in TypeScript

In TypeScript, Proxy objects serve as versatile tools for intercepting and customizing the behavior of JavaScript objects. By providing a mechanism to trap fundamental operations like property access, assignment, and function invocation, Proxy objects empower developers with advanced metaprogramming capabilities.

Proxy objects act as intermediaries between code and target objects, allowing developers to intercept and modify operations performed on the target. Essentially, a Proxy object wraps around the target object and provides a customizable interface for manipulating its behavior. A Proxy object consists of two essential components:

How proxy object manages operations and logs outputs through handlers interacting with a target object
How proxy object manages operations and logs outputs through handlers interacting with a target object
  1. Target object: This is the original object that the Proxy object is associated with. All operations performed on the Proxy object are ultimately delegated to the target object.

  2. Handler object: The handler object contains traps, which are functions that intercept specific operations on the target object. These traps allow developers to customize the behavior of the Proxy object by defining custom logic for various operations.

When do we need Proxy objects?

Proxy objects are particularly useful in scenarios where developers need to exert fine-grained control over object behavior. Let’s explore some common situations where Proxy objects can be beneficial:

  • Validation: Proxy objects can enforce data integrity by intercepting property access and modification. For instance, a Proxy can ensure only valid email addresses are assigned to a property.

  • Logging: By intercepting property access, assignment, and function calls, Proxy objects can log operations on objects, providing valuable insights for debugging and monitoring application flow.

  • Caching: Proxies can implement caching mechanisms to optimize performance. By intercepting property access, they can return cached values instead of recomputing them, which is beneficial for computationally expensive operations.

  • Security: Proxy objects can restrict access to certain properties or operations based on user roles or permissions, preventing unauthorized actions and protecting sensitive data.

  • Performance optimization: Proxies can defer resource-intensive operations until they are necessary, improving startup time and memory usage by delaying the initialization of complex objects until first access.

Proxy object features
Proxy object features

Creating a Proxy

To create a Proxy object in TypeScript, we utilize the Proxy constructor, passing in the target object and a handler object with trap methods. Let's explore this with an example:

// Creating a target object
const target = {
message: "Hello, World!",
value: 42
};
// Creating a handler object with traps
const handler = {
get(target: any, property: string) {
console.log(`Accessing property: ${property}`);
return target[property];
},
set(target: any, property: string, value: any) {
console.log(`Setting property: ${property} to ${value}`);
target[property] = value;
return true;
}
};
// Creating a Proxy object
const proxy = new Proxy(target, handler);
// Accessing and modifying properties through the Proxy
console.log(proxy.message); // Output: Accessing property: message; Hello, World!
proxy.value = 100; // Output: Setting property: value to 100

In this example, we define a target object with properties message and value. We then create a handler object with get and set traps to intercept property access and assignment operations. Finally, we create a Proxy object, proxy using the target and handler, enabling us to intercept and customize interactions with the target object.

Advanced Proxy usage

Beyond basic property access and assignment, Proxy objects offer a wide range of applications. Let’s explore some advanced scenarios:

  • Function Invocation: Proxy objects can intercept function calls on the target object, enabling additional logic or side effects to be applied before or after function execution.

const targetFunction = () => {
console.log("Executing target function");
};
const handlerFunction = {
apply(target: any, thisArg: any, args: any[]) {
console.log("Before executing target function");
const result = target.apply(thisArg, args);
console.log("After executing target function");
return result;
}
};
const proxyFunction = new Proxy(targetFunction, handlerFunction);
proxyFunction(); // Output: Before executing target function; Executing target function; After executing target function

In this example, we create a Proxy object, proxyFunction around a target function targetFunction. The apply trap intercepts the function call, allowing us to perform actions before and after executing the target function.

  • Property Deletion: Proxy objects can intercept property deletion operations, enabling validation or additional cleanup logic to be applied.

const targetObject = {
name: "John",
age: 30
};
const handlerObject = {
deleteProperty(target: any, property: string) {
console.log(`Deleting property: ${property}`);
delete target[property];
return true;
}
};
const proxyObject = new Proxy(targetObject, handlerObject);
delete proxyObject.age; // Output: Deleting property: age

Here, we create a Proxy object, proxyObject around a target object targetObject. The deleteProperty trap intercepts the deletion of properties, allowing us to log the operation and perform cleanup if necessary.

Conclusion

Proxy objects in TypeScript offer unparalleled flexibility and control over object operations, making them invaluable tools for metaprogramming, validation, and advanced application development. By mastering the creation and usage of Proxy objects, developers can unlock new dimensions of customization and optimization in their TypeScript projects.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved