A last-write-wins (LWW) map is a conflict-free replicated data type (CRDT) where each key holds the value from the write with the highest timestamp, and equal timestamps are broken by the writer's node id so every replica independently agrees on the same winner. It lets many machines edit the same map while disconnected and later merge their states in any order, always converging on one result. Resolving conflicts by last-write-wins timestamp is exactly how Cassandra settles competing column writes and how Riak's LWW registers converge.
Build a factory lwwRegisterMapCrdt(nodeId) that returns a map whose writes carry a timestamp and whose replicas merge deterministically. Each key stores one stamped entry, { value, ts, node, deleted }, and a write replaces the current entry only when its (ts, node) pair is greater.
function lwwRegisterMapCrdt(nodeId: string): {
set(key: string, value: unknown, timestamp: number): void;
get(key: string): unknown | undefined;
has(key: string): boolean;
delete(key: string, timestamp: number): void; // stores a tombstone
merge(other): void; // fold another replica's state in
entries(): Array<[string, unknown]>; // live keys only
};
const a = lwwRegisterMapCrdt('a');
a.set('color', 'red', 1);
a.set('color', 'blue', 2); // higher timestamp wins
a.get('color'); // 'blue'
a.delete('color', 3); // tombstone at ts 3 beats the ts 2 write
a.has('color'); // false
// Two replicas write 'color' at the SAME timestamp, then merge.
const a = lwwRegisterMapCrdt('node-a');
const b = lwwRegisterMapCrdt('node-b');
a.set('color', 'red', 5);
b.set('color', 'green', 5);
a.merge(b); // tie on ts 5: 'node-b' > 'node-a', so green wins
a.get('color'); // 'green' (b.merge(a) gives the same answer)
{ value, ts, node, deleted }; set and delete stamp the entry with the given timestamp and this replica's nodeId.nodeId is larger by string comparison. An equal (ts, node) pair never overwrites.delete stores a deleted: true entry that wins or loses by the same rule, so a later delete removes a key and a later set resurrects it. get, has, and entries hide tombstoned keys.merge keeps the greater (ts, node) per key, which makes it commutative, associative, and idempotent: replicas converge no matter the order writes and merges arrive in.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.