I'm trying to add, for example a isEmpty
getter to the Object
or Array
, but I'm having trouble to do so because I think I'm not really understanding how to access properties through this
:
declare global {
interface Object {
isEmpty: boolean;
}
}
// 1. Doesn't work
Object.prototype.isEmpty = this.keys.length === 0;
// 2. Doesn't work either
Object.prototype.isEmpty = Object.keys(this).length === 0;
Is it really possible to make this work? How would it be with Array
?
References:
- How to properly extend Array prototype in Typescript 4.0.3?
- Bobby Hadz's How to Extend Object.prototype in TypeScript
CodePudding user response:
⚠ WARNING! ⚠
IT IS WIDELY CONSIDERED BAD PRACTICE TO MODIFY NATIVE PROTOTYPES, mainly because it might change the code — specially its behavior — other programmers depend on.
See Why is extending native objects a bad practice? for more information. In what follows I'm going to show how to do it, but this is not meant to say that you should do it. A standalone isEmpty()
function would work just as well, and is far less controversial.
Do check out @Dimava's answer as well, as he shows yet another way of doing this.
If you want to append a getter to an existing object, then you need to use the Object.defineProperty()
method.
Your example could therefore look like:
// declare global { // <-- needed within modules
interface Object {
isEmpty: boolean;
}
// }
Object.defineProperty(Object.prototype, "isEmpty", {
configurable: true, get() { return Object.keys(this).length === 0 }
});
And you can verify that it works as desired:
const a = { z: 1 };
console.log(a.isEmpty) // false
const b = {};
console.log(b.isEmpty) // true
CodePudding user response:
In this way it's easy to make extensions, and you don't have to worry about correct descriptors (making them non-enumerable, etc) and correct typing
class ObjectExtension extends Object {
get isEmpty() {
return Object.keys(this).length === 0;
}
}
function extendSuperclassPrototype(classExtension: new (...a: any[]) => any): void {
let desc = Object.getOwnPropertyDescriptors(classExtension.prototype);
delete (desc as any).constructor;
let superproto = Object.getPrototypeOf(classExtension).prototype;
Object.defineProperties(Object.prototype, desc);
}
declare global {
interface Object {
isEmpty: ObjectExtension['isEmpty']
}
}
extendSuperclassPrototype(ObjectExtension)
console.log(({a: 1}).isEmpty, ({}).isEmpty)