<script type=module>
    let tick = 0
  
	// This interval tests to see if the entry in the TwoWayWeakMap is collected.
    const loop = setInterval(() => {
        const obj = window.map.keyFrom(42)
    
        // logs undefined once enough time elapsed for `o` to be collected
        console.log(`o still exists? (${tick++})`, !!obj)
    
        if (!obj) {
            clearInterval(loop)
            console.log('o was collected!')
        }
    }, 300)
</script>

<script type=module>
    class TwoWayWeakMap /*<K extends object = object, V = unknown>*/
      extends WeakMap /*<K, V>*/ {
    
        #refs /*: Set<WeakRef>*/ = new Set();
    
        constructor() {
            super();
            setInterval(() => this.maybeCleanup(), 1000);
        }
    
        set(k /*: K*/ , v /*: V*/ ) /*: void*/ {
            super.set(k, v);
            this.#refs.add(new WeakRef(k));
        }
    
        keyFrom(v /*: V*/ ) /*: K | undefined*/ {
            for (const ref of this.#refs) {
                // Possibly clean up while we're at it.
				const o = ref.deref();
                if (!o) {
                    this.#refs.delete(ref);
                    continue;
                }
				
                if (this.get(o) === v) return o;
            }
        }
    
        maybeCleanup() {
            for (const ref of this.#refs) {
                const o = ref.deref();
                if (!o) this.#refs.delete(ref);
            }
        }
    }
  
    class SomeClass {}

    function main() {
        const map = (window.map = new TwoWayWeakMap /*<SomeClass, number>*/());
        const o = new SomeClass();
        map.set(o, 42);
        console.log("value?", map.get(o)); // logs "42"
        console.log("object?", !!map.keyFrom(42)); // logs true if it exists
    }
  
    main();
  
    // At this point there is no reference to `o`, except by
    // WeakRef and WeakMap, so `o` should be collectable.
</script>
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.