class-signals
Version:
OOP-Style events
138 lines (94 loc) β’ 3.26 kB
Markdown
[](https://www.npmjs.com/package/class-signals)
[](https://github.com/your-username/class-signals/blob/main/LICENSE)
# π― 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
```ts
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.
```ts
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.
```ts
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.
```ts
const controller = new ProtectedSignalController<number>()
controller.signal.subscribe((v) => console.log(v))
controller.activate(1)
```
- `activate(payload)`
- `signal` β the exposed read-only `ProtectedSignal<T>`
## π‘ Recommended Patterns
### β
Expose only whatβs needed
```ts
class AuthService {
#changed = new ProtectedSignalController<void>()
public readonly onChange = this.#changed.signal
login() {
this.#changed.activate()
}
}
```
### βοΈ Auto-unsubscribe with AbortSignal
```ts
const controller = new AbortController()
signal.subscribe(fn, { signal: controller.signal })
controller.abort()
```
### π§± Object-based subscribers
```ts
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
- `AbortSignal` and `once` built-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.