diff --git a/client/src/util.ts b/client/src/util.ts
new file mode 100644
index 0000000..2d8b29e
--- /dev/null
+++ b/client/src/util.ts
@@ -0,0 +1,16 @@
+// Performs a type-agnostic deep comparison of two values by process of elimination. This mainly covers the use cases of Primitives, Objects and Arrays, but not certain builtins like Dates.
+export function equals(a: any, b: any): boolean {
+ if (typeof a !== typeof b) return false; // Different types can't be equal, except number and bigint but who cares. Null and undefined are considered different.
+ if (typeof a !== 'object') return a === b; // A simple comparison suffices for non-objects
+ if (isNullish(a) !== isNullish(b)) return false; // A common use case is checking for something to exist vs. not, so it's covered explicitly here
+ if (isNullish(a) && isNullish(b)) return true;
+ if (a instanceof Array && !(b instanceof Array)) return false; // Could be generalized with Object.getPrototypeOf, but I think it's preferable to have "pure" and regular objects match (Look up Object.create(null))
+ if (a?.length !== b?.length) return false; // Another not technically necessary but common point of comparison.
+ for (const key of new Set(Object.keys(a).concat(Object.keys(b)))) // All there's left is to deep-compare what are clearly objects. The keys of both need to be merged to prevent an extra key on one side being ignored.
+ if (!equals(a[key], b[key])) return false;
+ return true; // Only once all points of inequality are rules out can we say for certain that the two values are equal.
+}
+
+export function isNullish(value: any) {
+ return !!(value === null || value === undefined);
+}
\ No newline at end of file