notes

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

typescript_channels.txt (1482B)


      1 -------------------------------------------------------------------------------
      2 TypeScript Channels/Signals Pattern
      3 -------------------------------------------------------------------------------
      4 
      5 The Implementation
      6 
      7 ```typescript
      8 export type Channel<T> = {
      9   subscribe(fn: (v: T) => void): () => void;
     10   next(value: T): void;
     11 };
     12 
     13 export function createChannel<T>(): Channel<T> {
     14   const subs = new Set<(v: T) => void>();
     15   return {
     16     subscribe(fn) {
     17       subs.add(fn);
     18       return () => subs.delete(fn);
     19     },
     20     next(value) {
     21       for (const fn of subs) fn(value);
     22     },
     23   };
     24 }
     25 ```
     26 
     27 Example
     28 
     29 ```typescript
     30 const messages = createChannel<string>();
     31 
     32 // producer: a websocket handler that knows nothing about the UI
     33 ws.onmessage = (e) => messages.next(e.data);
     34 
     35 // consumer: a component that knows nothing about the websocket
     36 useEffect(() => messages.subscribe((m) => setLog((p) => [...p, m])), []);
     37 ```
     38 
     39 Explanation
     40 
     41 A channel is just a set of callbacks plus two operations: `subscribe` adds one
     42 and hands back a function that removes it, and `next` calls every callback with
     43 a value. That is the whole primitive — no buffering, no replay, no async. Its
     44 value is decoupling: the producer only knows how to emit, the consumer only
     45 knows how to listen, and neither imports the other. Unsubscribing is the one
     46 thing you must not forget, which is why `subscribe` returns the cleanup
     47 function directly — in React, returning it from `useEffect` is all the teardown
     48 you need.