Skip to content

Add a general NestedMap solution to the sdk #5033

@toger5

Description

@toger5

In this PR it became apperant that we do not have a good nested map solution.
This comment (by @robintown) proposes a good solution:
#5028 (comment)

In fact, this pattern of shuffling around nested maps is so common in the JS SDK that I feel like it deserves to be turned into a set of reusable functions. It takes a bit of type magic, but I played around with it a bit and I think something like this would make for a pretty convenient API:

type NestedMap<K extends unknown[], V> = K extends [infer K1, ...infer K_] ? Map<K1, NestedMap<K_, V>> : V

function getNested<K extends [unknown, ...unknown[]], M extends NestedMap<K, unknown>>(map: M, ...keys: K): M extends NestedMap<K, infer V> ? V | undefined : never {
    let result: any = map
    for (const key of keys) result = result?.get(key)
    return result
}

function setNested<K extends [unknown, ...unknown[]], V, M extends NestedMap<K, V>>(map: M, value: V, ...keys: K): void {
    let m: any = map
    for (let i = 0; i < keys.length - 1; i++) {
        let inner = m.get(keys[i])
        if (inner === undefined) {
            inner = new Map()
            m.set(keys[i], inner)
        }
        m = inner
    }
    m.set(keys[keys.length - 1], value)
}

function deleteNested<K extends [unknown, ...unknown[]], M extends NestedMap<K, unknown>>(map: M, ...keys: K): boolean {
    if (keys.length === 1) {
        return map.delete(keys[0])
    } else {
        const inner = map.get(keys[0]) as Map<unknown, unknown> | undefined
        if (inner === undefined) return false
        const [key, ...keys_] = keys
        // @ts-ignore
        const result = deleteNested(inner, ...keys_)
        if (inner.size === 0) map.delete(key)
        return result
    }
}

Usage looks like this:

const myMap = new Map<number, Map<string, number>>()
setNested(myMap, 999, 1, 'foo')
const y = getNested(myMap, 1, 'foo') // y = 999
deleteNested(myMap, 1, 'foo') // now myMap is empty

Then with nested maps of 3+ layers being less painful, this could even help us avoid the ${stickyKey}${sender} hack found in this file.

This change was not added as part of #5028.

This issue tracks adding such a feature and using it in all places of the js-sdk where it is helpful.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions