Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Created July 3, 2026 06:11
Show Gist options
  • Select an option

  • Save dfkaye/091a4e9846b3a2df6e5677dbac9377ee to your computer and use it in GitHub Desktop.

Select an option

Save dfkaye/091a4e9846b3a2df6e5677dbac9377ee to your computer and use it in GitHub Desktop.
test (rant): store an instance as JSON and revive it as an instance of the same class
// 2 July 2026
// store an instance as JSON and revive it as an instance of the same class
// I haven't written one of these in a couple years (2024). This one is in
// response to an infuriatingly ignorant justification for using TypeScript
// *because compiler* instead of the more pleasant and correct destructured
// parameter pattern in class function definitions.
// I don't know this person but too much ignorance goes unremarked nowadays
// among so-called professional front-end web developers when it should be
// combated and corrected.
// The post in question:
// https://taxorubio.com/blog/type-definitions-to-retrieve-objects-from-localstorage/
// This is my test, there are (or should be) many like it, but this
// one is mine. There are two classes under scrutiny in the post. I take
// liberties modifying them here to show you don't need a compiler or a
// set of typedefs to accomplish the objective (save data from a widget instance, retrieve that data and revive as a new widget instance).
// The modified Widget class demonstrates that what you really need are
// destructured parameters, not values. The modified DB class demonstrates
// the changes needed to enforce that pattern during storage and retrieval.
~(function() {
class DB {
constructor(storage) {
this.storage = storage;
// Map of constructors by storage key.
// Yes, that makes two storage mechanisms to track instead of one.
// This one lets us prevent modifying storage with mere values.
this.map = new Map();
}
get(key) {
var constructor = this.map.get(key);
// If we haven't mapped a constructor, we haven't stored an item
// for this key.
if (!constructor) {
return console.error(`No item stored at key ${ key }`);
}
var json = this.storage.getItem(key);
var value = JSON.parse(json);
return new constructor(value);
}
set(key, data) {
if (data !== Object(data)) {
return console.error(
`data must be an object, not a primitive, ${ data }`
);
};
this.map.set(key, data.constructor);
var json = JSON.stringify(data);
return this.storage.setItem(key, json);
}
}
class Widget {
// what you really need are destructured parameters, not values
constructor({ value }) {
// This line is incomprehensibly missing from original example.
this.value = parseFloat(value);
}
// I've added a private method to test from prototype method
#test() {
console.warn(
"*private method test*",
"\npublic value:", this.value
);
}
isEven() {
// test private method call from prototype
this.#test();
return this.value % 2 == 0;
}
}
// The correct solution starts by requiring that our widget receive an
// object to be destructured, not a value...
var widget = new Widget({ value: "234" });
console.log("our widget:", "\nisEven:", widget.isEven(), "\nvalue:", widget.value);
var group = "did it work?";
console.group(group);
var db = new DB(localStorage);
db.set("widget", widget);
var restored = db.get("widget");
console.assert(restored.isEven(), "should work");
console.groupEnd(group);
console.group("null");
var key = "dsaflk;jsdf;lkaseroiiauewrpaoesrfapojdsf";
console.assert(
db.get(key) == null,
`should return null for key "${ key }"`
);
db.set(key, {value: key});
console.assert(
db.get(key).value === key,
`should return value for key "${ key }"`
);
console.groupEnd("null");
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment