Today, during some testing, I was interested in seeing all properties of an Error object.
I wrote this Method to get all available properties, not caring about ‘hasOwnProperty’.
/**
* Get all properties of an object and don't care about enumerable or prototyp.
*
* @internal
* @param {object} obj
* @return {[string, unknown][]}
*/
export function getAllProperties(obj: object): [string, unknown][] {
const properties: [string, unknown][] = [];
const prototypChain: string[] = [];
let currentObj = obj;
while (currentObj !== Object.prototype && currentObj !== null) {
Object.getOwnPropertyNames(currentObj).forEach((key) => {
if (prototypChain.length > 0) {
// @ts-expect-error I want it this way!
properties.push([`${prototypChain.join('.')}.${key}`, currentObj[key]]);
} else {
// @ts-expect-error I want it this way!
properties.push([key, currentObj[key]]);
}
});
currentObj = Object.getPrototypeOf(currentObj);
prototypChain.push('prototyp');
}
return properties;
}
Imagine my surprise when I used it to look at an error thrown with new Error('...')
.
{
stack: "Error: This is a test error
at Object.<anonymous> (/Users/.../Entwicklung/Bit/bit-log/src/appender/__tests__/FileAppender.spec.ts:256:13)",
message: "This is a test error",
prototyp.constructor: [Function function Error() { [native code] }],
prototyp.name: "Error",
prototyp.message: "",
prototyp.toString: [Function function toString() { [native code] }]
}
How is it possible to have an object with inheritance that does not correctly overwrite a property in the parent?
Or is my expectation wrong that there should not be two different message properties?
After all, this is a standard object and not a custom implementation.