Reflect.defineProperty()
Reflect.defineProperty() defines (adds or changes) an object property with a given descriptor and returns a boolean value telling you whether it succeeded. It is the modern counterpart of Object.defineProperty(), but with more predictable and safer behaviour: here a failure is an ordinary result rather than an exception.
Theory
TL;DR
- Syntax:
Reflect.defineProperty(target, propertyKey, descriptor). - Returns
trueon success andfalseon failure, not the object itself. - It does not throw on failure, so no
try/catchis needed. - It accepts both a data descriptor (
value,writable) and an accessor descriptor (get,set). - Keys can be a string or a
Symbol. - Main uses: safe checks, metaprogramming and
Proxytraps.
Quick example
const user = {};
const result = Reflect.defineProperty(user, 'name', {
value: 'Maria',
writable: true,
enumerable: true,
configurable: true
});
console.log(result); // true
console.log(user.name); // "Maria"This is the same as Object.defineProperty(user, 'name', { ... }), with one important difference: Reflect does not throw an error, it simply returns false.
Signature and arguments
Reflect.defineProperty(target, propertyKey, descriptor)| Argument | Description |
|---|---|
target | The object on which the property is defined |
propertyKey | The property name (a string or a Symbol) |
descriptor | The descriptor, an object with flags (value, writable, enumerable, configurable, get, set) |
What it returns:
trueif the property was defined successfully;falseif the operation failed (for example, the object is protected byObject.freeze()or the property is non-configurable).
Difference from Object.defineProperty()
| Behaviour | Object.defineProperty() | Reflect.defineProperty() |
|---|---|---|
| Returns | the object itself | true / false |
| On failure | throws an exception | returns false |
| Suited to | ordinary code | safe, "reflective" operations |
"Reflective" means working with the internal properties of objects without throwing errors.
A safe check in practice:
const frozen = Object.freeze({});
try {
Object.defineProperty(frozen, 'x', { value: 1 });
} catch (e) {
console.log('Error:', e.message);
}
console.log(Reflect.defineProperty(frozen, 'x', { value: 1 })); // false, no exceptionReflect.defineProperty() simply returns false instead of throwing.
Descriptors: data and accessor
The method works identically for data and accessor descriptors:
const person = {};
Reflect.defineProperty(person, 'fullName', {
get() {
return 'Maria Koval';
},
enumerable: true
});
console.log(person.fullName); // "Maria Koval"Here the property is described by a getter rather than a value, and Reflect.defineProperty() accepts such a descriptor without any caveats.
Defining properties dynamically and conditionally
The method is convenient inside a loop, when the set of keys is only known at run time:
const obj = {};
['name', 'age', 'city'].forEach(key => {
Reflect.defineProperty(obj, key, {
value: key.toUpperCase(),
enumerable: true
});
});
console.log(obj);
// { name: 'NAME', age: 'AGE', city: 'CITY' }The return value is useful directly inside a condition:
if (Reflect.defineProperty(user, 'role', { value: 'admin' })) {
console.log('Property added successfully');
} else {
console.log('Failed to add property');
}This is handy precisely because it requires no try/catch: the result is checked like any other boolean expression.
Working with Proxy
Inside a Proxy defineProperty trap, Reflect.defineProperty is used to delegate the default behaviour:
const target = {};
const proxy = new Proxy(target, {
defineProperty(target, key, descriptor) {
console.log(`Defining property "${String(key)}"`);
return Reflect.defineProperty(target, key, descriptor);
}
});
proxy.x = 10; // under the hood this calls Reflect.defineProperty automaticallyIn a Proxy, the reflective methods (Reflect.*) make it easy to implement behaviour as naturally as possible: the trap signature matches the signature of the matching Reflect method, and the boolean result is exactly what the trap is supposed to return.
Summary table:
| Question | Answer |
|---|---|
| What it does | Defines (creates or changes) an object property with the given descriptor |
| What it returns | true on success, false on failure |
| Does it throw | No |
| Does it use a descriptor | Yes (value, writable, configurable, enumerable, get, set) |
| Where it is used | Safe operations, Proxy, metaprogramming |
Common mistakes
- Expecting the method to return an object.
Object.defineProperty()returns the object and therefore chains, whileReflect.defineProperty()returnstrue/false. WritingReflect.defineProperty(obj, 'a', d).bwill break. - Ignoring the return value. Since there is no exception, a silent failure goes unnoticed. If the result matters, check it.
- Wrapping the call in
try/catch"just in case". For a failed property definition that is pointless: the whole point ofReflectis to avoid the exception. An exception is only possible for invalid arguments, for example whentargetis not an object. - Forgetting that the flags default to
false. The descriptor{ value: 1 }creates a property that is notwritable,enumerableorconfigurable, so it will not show up inObject.keys()and will not change on assignment. - Confusing it with
Reflect.getOwnPropertyDescriptor(). The first sets a descriptor, the second reads one.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.