class-signals
v2.0.2
Published
OOP-Style events
Downloads
36
Maintainers
Readme
🎯 signal-system
Reactive signaling for class-based TypeScript — safe, simple, and expressive.
A small, focused library for creating and managing reactive signals in object-oriented JavaScript and TypeScript.
Use it to broadcast changes, listen to internal events, and expose read-only observables — all with strong typing and no boilerplate.
⚡ Quick Example
import { Signal } from "signal-system"
const onMessage = new Signal<string>()
onMessage.subscribe((text) => {
console.log("📩 Message received:", text)
})
onMessage.activate("Hello, world!")✅ For safe, read-only signal exposure, use
ProtectedSignal+ProtectedSignalController
🧠 Public API
🔔 Signal<T>
A reactive signal that allows both subscribing and activating updates. Great for local event buses, live data updates, or observable service events.
const signal = new Signal<number>()
signal.subscribe((v) => console.log("Received:", v))
signal.activate(42)subscribe(fn, options?)unsubscribe(fn, options?)activate(payload)
🔒 ProtectedSignal<T>
A read-only signal: lets others subscribe, but only you can activate it. Designed for safe reactive encapsulation.
class Store {
#events = new ProtectedSignalController<string>()
public readonly onChange = this.#events.signal
update() {
this.#events.activate("updated")
}
}subscribe(fn, options?)unsubscribe(fn, options?)
🛠️ ProtectedSignalController<T>
Holds the power to trigger a protected signal.
Perfect for internal logic, paired with a ProtectedSignal for external safety.
const controller = new ProtectedSignalController<number>()
controller.signal.subscribe((v) => console.log(v))
controller.activate(1)activate(payload)signal— the exposed read-onlyProtectedSignal<T>
💡 Recommended Patterns
✅ Expose only what’s needed
class AuthService {
#changed = new ProtectedSignalController<void>()
public readonly onChange = this.#changed.signal
login() {
this.#changed.activate()
}
}✂️ Auto-unsubscribe with AbortSignal
const controller = new AbortController()
signal.subscribe(fn, { signal: controller.signal })
controller.abort()🧱 Object-based subscribers
signal.subscribe({
handleSignal(value) {
console.log("Handled:", value)
},
})🤔 Why not EventTarget / EventEmitter?
- No event names to manage (
"change","data"— gone!) - Fully typed payloads
- Easy read-only APIs
AbortSignalandoncebuilt-in- Focused: no bubbling, no DOM quirks, no legacy cruft
🧩 Use Signal when you need control.
🔒 Use ProtectedSignal to expose safe subscriptions.
⚙️ Use ProtectedSignalController to manage internal dispatch.
That’s it. Clean signals for class-based codebases.
