/** * Like `return map[key] ??= fallback(key)` but for {@link Map}. * @param map the target map * @param key element key * @param fallback default element value * @returns existing value or fallback */ export function getOrSetMap(map: Map, key: K, fallback: (key: K) => V) { if (!map.has(key)) map.set(key, fallback(key)) return map.get(key) as V } /** * Like `key => map[key] || fallback()` but for {@link Map}. * @param map the target map * @param fallback value if missing in the map * @returns a getter into the map */ export function getMapWithDefault(map: Map, fallback: () => V) { return (key: K) => (map.has(key) ? (map.get(key) as V) : fallback()) } export type Dict = Partial> /** * Create a new {@link Dict} * @returns an empty dict */ export function newDict() { return {} as Dict } /** * Iterate over {@link Dict} entries * @param d target dict * @returns array of key value pairs */ export function iterDict(d: Dict) { return Object.entries(d) as unknown as readonly [K, V][] } /** * Like `d[k] = v` but delete the key if {@link v} is undefined. * @param d target dict * @param k key to set * @param v value to set * @returns the value */ export function setOrDelete(d: Dict, k: K, v: V) { if (v !== undefined) d[k] = v // eslint-disable-next-line @typescript-eslint/no-dynamic-delete else delete d[k] return v }