Add utility for tracking Signal reads in a callback
The current best way to get a list of signals read during a callback is through a function like this
function observeReads<T>(cb: () => T): {result: T, signals: ReadonlyArray<Signal<unknown>>} {
const computed = new Signal.computed(cb);
const result = computed.get();
const signals = Signal.subtle.introspectSources(computed);
return {result, signals};
}
This is unnecessarily heavy for most use cases. Additionally, it is possible that the internal computed could end up as a Consumer for one of the read signals, making it persist in memory beyond the end of the utility function.
I think a utility like observeReads should be added to the spec, though obviously with a cheaper implementation, designed for occasions when the callback does not need to be reactively re-invoked.
The case I have in mind is for writing a check that no Signals are read in a callback. This is important in contexts where Signals are expected to be passed around, not invoked.
Imagine an API like this:
bindClassNameValue(domNode: HtmlElement, classNames: string | Signal<string>) {
if (typeof classNames === 'string') {
domNode.className = classNames;
} else {
untrack(() => effect(() => {
domNode.className = classNames.get();
}));
}
}
It would be harmful if people invoked that API as bindClassNameValue(node, myClassNames.get()) on accident, so a framework could monitor and throw errors if any signals are read at inappropriate times.