# event

A typed, generic event bus for decoupled communication between components.

---

## `class EventHandler<EventMap>`

A strongly-typed event emitter. Consumers define an `EventMap` that maps event type names to their payload types, ensuring compile-time safety for both dispatching and listening.

### Type Parameter

| Name | Constraint | Description |
|------|-----------|-------------|
| `EventMap` | `Record<string, Record<string, unknown> \| void>` | Maps each event name to its payload type, or `void` for events with no payload. |

### Example type definition

```typescript
type MyEvents = {
    resize: { width: number; height: number }
    reset: void
}

const bus = new EventHandler<MyEvents>()
```

---

## `addListener(type, callback) → () => void`

Registers a listener for the given event type. Returns a cleanup function that removes the listener when called.

### Parameters

| Name | Type | Description |
|------|------|-------------|
| `type` | `keyof EventMap` | The event type to listen for. |
| `callback` | `EventListener<EventMap, T>` | The function to call when the event fires. Receives an event object with `type`, `target`, and (for non-void events) `value`. |

### Returns

`() => void` — Call this to unsubscribe.

### Example

```typescript
const unsubscribe = bus.addListener('resize', (e) => {
    console.log(e.value.width, e.value.height)
})

// Later:
unsubscribe()
```

### Notes

- Throws `"Listener callback already exists."` if the **same function reference** is registered twice for the same event type.

---

## `addListenerOnce(type, callback) → void`

Registers a listener that fires exactly once, then auto-removes itself.

### Parameters

| Name | Type | Description |
|------|------|-------------|
| `type` | `keyof EventMap` | The event type to listen for. |
| `callback` | `EventListener<EventMap, T>` | Called on the first dispatch of the event. |

### Notes

- Throws `"Listener callback already exists."` if the same function reference is registered twice.
- Does not return a cleanup function (unlike `addListener`).

---

## `removeListener(type, callback) → void`

Explicitly removes a previously registered listener.

### Parameters

| Name | Type | Description |
|------|------|-------------|
| `type` | `keyof EventMap` | The event type the listener was registered under. |
| `callback` | `EventListener<EventMap, T>` | The exact function reference that was registered. |

### Notes

- Throws if no listeners are registered for `type`.
- Throws `"Listener callback cannot be found"` if `callback` is not in the listener list.
- Prefer using the cleanup function returned by `addListener` over calling `removeListener` directly.

---

## `dispatchEvent(type, value?) → void`

Fires all listeners registered for `type` with the given payload.

### Parameters

| Name | Type | Description |
|------|------|-------------|
| `type` | `keyof EventMap` | The event type to fire. |
| `value` | `EventMap[T]` | The payload. Omit or pass `undefined` for `void` events. |

### Notes

- Is a no-op if no listeners are registered for `type`.
- Each listener receives an event object: `{ type, target, value? }`.

---

## Types

### `Event<EventMap, EventType>`

```typescript
interface Event<EventMap, EventType> {
    type: EventType
    target: EventHandler<EventMap>
    value: EventMap[EventType]
}
```

### `VoidEvent<EventMap, EventType>`

```typescript
interface VoidEvent<EventMap, EventType> {
    type: EventType
    target: EventHandler<EventMap>
}
```

### `EventListener<EventMap, EventType>`

Conditional type that resolves to a void-event or value-event listener signature depending on whether `EventMap[EventType]` is `void`.
