Working on a utility library designed to enhance the functionality of a complex API model that receives JSON-parsed objects. These objects come with specific structure guarantees, as outlined below:
// Defined message structure:
interface InputBox {
top: number;
height: number;
left: number;
width: number;
}
interface InputObj {
box: InputBox
}
// Example of user code processing the data:
const inputObj: InputObj = JSON.parse(
'{ "box": { "top": 0, "height": 10, "left": 1, "width": 2, "color": "red" } }'
);
The objective is to create a modified version of these objects that:
- Includes additional utility functions and properties
- Stringifies into JSON that is compatible with the original input
- Maintains consistent behavior when treated as mutable
- Preserves any unexpected attributes if possible
For instance, the user's code may appear as follows:
// Both in-place modification or new object creation are acceptable:
const easyObj = myCoolLibrary(inputObj);
easyObj.box.top = 5;
console.log(easyObj.box.getBottom()); // '15'
JSON.stringify(easyObj);
// -> { "box": { "top": 5, "height": 10, "left": 1, "width": 2, "color": "red" } }
// (Note that box.color remains present, although not part of the initial interface)
After exploring various options, it appears that:
- An in-place solution using Object.setPrototypeOf to directly overwrite prototypes in the input could be effective, but compatibility with older browsers might require polyfilling.
- Creating new objects (via classes/prototypes) and transferring properties using Object.assign could also work since the input objects are simple JSON-able
Object
s... However, this method may still need polyfilling for IE, but could be more standardized?
The challenge lies in implementing these methods while ensuring TypeScript compatibility:
class MyCoolBox implements InputBox {
constructor(box: InputBox) {
Object.assign(this, box);
}
getBottom() {
return this.top + this.height;
}
}
// > Class 'MyCoolBox' incorrectly implements interface 'InputBox'.
// (and does not recognize properties like .top, .height)
Object.setPrototypeOf(inputObj.box, MyCoolBox);
inputObj.box.getBottom();
// > Property 'getBottom' does not exist on type 'InputBox'
// Fails to acknowledge the change in interface.
Is there a practical approach that TypeScript would comprehend? It seems reasonable to want to augment a JSON-parsed object (with a defined interface) with additional methods!