Skip to content

signalMap()

A reactive Map-shaped collection where each key has its own subscriber set. Effects that read a specific key via .get() or .has() re-run only when that key changes — effects that iterate or read .size re-run on any structural change.

Shipped from the sub-path @whisq/core/collections, not the main entry.

import { signalMap } from "@whisq/core/collections";
function signalMap<K, V>(
initial?: Iterable<readonly [K, V]>,
): SignalMap<K, V>;
interface SignalMap<K, V> {
get(key: K): V | undefined;
has(key: K): boolean;
set(key: K, value: V): SignalMap<K, V>;
delete(key: K): boolean;
clear(): void;
readonly size: number;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
[Symbol.iterator](): IterableIterator<[K, V]>;
forEach(fn: (value: V, key: K, map: SignalMap<K, V>) => void): void;
}
ParamTypeDescription
initialIterable<readonly [K, V]>Optional initial key/value pairs
  • .get(key) / .has(key) — subscribe only to key. Writes to other keys don’t re-run your effect.
  • .size, iteration, .keys() / .values() / .entries() / .forEach() — subscribe to structural changes (add/delete/clear).
  • .set(key, value) — notifies subscribers of key (and .size subscribers if it’s a new key).
import { effect } from "@whisq/core";
import { signalMap } from "@whisq/core/collections";
interface User { name: string }
const users = signalMap<string, User>();
users.set("u1", { name: "Alice" });
effect(() => {
// Tracks "u1" only — other inserts don't re-run this.
console.log(users.get("u1")?.name);
});
users.set("u2", { name: "Bob" }); // effect does NOT re-run
users.set("u1", { name: "Carol" }); // effect re-runs

Use signalMap when you keep a dictionary keyed by stable IDs and want per-ID subscriptions — it avoids the O(N) re-run cost of a single signal<Record<K, V>> on every mutation.