Validating Properties Using the set
Trap
Suppose you want to create an object whose property values must be numbers. That means every new property added to the object must be validated, and an error must be thrown if the value isn’t a number. To accomplish this, you could define a set
trap that overrides the default behavior of setting a value. The set
trap receives four arguments:
trapTarget
- the object that will receive the property (the proxy’s target)key
- the property key (string or symbol) to write tovalue
- the value being written to the propertyreceiver
- the object on which the operation took place (usually the proxy)
Reflect.set()
is the set
trap’s corresponding reflection method, and it’s the default behavior for this operation. The Reflect.set()
method accepts the same four arguments as the set
proxy trap, making the method easy to use inside of the trap. The trap should return true
if the property was set or false
if not. (The Reflect.set()
method returns the correct value based on whether the operation succeeded.)
To validate the values of properties, you’d use the set
trap and inspect the value
that is passed in. Here’s an example:
let target = {
name: "target"
};
let proxy = new Proxy(target, {
set(trapTarget, key, value, receiver) {
// ignore existing properties so as not to affect them
if (!trapTarget.hasOwnProperty(key)) {
if (isNaN(value)) {
throw new TypeError("Property must be a number.");
}
}
// add the property
return Reflect.set(trapTarget, key, value, receiver);
}
});
// adding a new property
proxy.count = 1;
console.log(proxy.count); // 1
console.log(target.count); // 1
// you can assign to name because it exists on target already
proxy.name = "proxy";
console.log(proxy.name); // "proxy"
console.log(target.name); // "proxy"
// throws an error
proxy.anotherName = "proxy";
This code defines a proxy trap that validates the value of any new property added to target
. When proxy.count = 1
is executed, the set
trap is called. The trapTarget
value is equal to target
, key
is "count"
, value
is 1
, and receiver
(not used in this example) is proxy
. There is no existing property named count
in target
, so the proxy validates value
by passing it to isNaN()
. If the result is NaN
, then the property value is not numeric and an error is thrown. Since this code sets count
to 1
, the proxy calls Reflect.set()
with the same four arguments that were passed to the trap to add the new property.
When proxy.name
is assigned a string, the operation completes successfully. Since target
already has a name
property, that property is omitted from the validation check by calling the trapTarget.hasOwnProperty()
method. This ensures that previously-existing non-numeric property values are still supported.
When proxy.anotherName
is assigned a string, however, an error is thrown. The anotherName
property doesn’t exist on the target, so its value needs to be validated. During validation, the error is thrown because "proxy"
isn’t a numeric value.
Where the set
proxy trap lets you intercept when properties are being written to, the get
proxy trap lets you intercept when properties are being read.