@mirawision/observer
Version:
A lightweight and flexible observer pattern implementation for TypeScript, providing a simple way to implement event-driven architecture with type safety.
241 lines (176 loc) • 5.59 kB
Markdown
# /observer
A lightweight and flexible observer pattern implementation for TypeScript, providing a simple way to implement event-driven architecture with type safety. This library offers a clean and intuitive API for implementing the observer pattern in your applications.
## Features
- **Type Safety**: Full TypeScript support with generic types for type-safe event data
- **Simple API**: Clean and intuitive interface for subscribing, unsubscribing, and notifying observers
- **Memory Efficient**: Uses Set for efficient observer management and automatic cleanup
- **Flexible**: Generic implementation allows for any data type to be passed to observers
- **Lightweight**: Minimal footprint with no external dependencies
- **Unsubscribe Support**: Individual and bulk unsubscribe methods for proper cleanup
## Installation
```bash
npm install /observer
```
or
```bash
yarn add /observer
```
## Usage
### Basic Example
```typescript
import { Observer } from '@mirawision/observer';
// Create an observer instance for string events
const observer = new Observer<string>();
// Subscribe to events
const listener1 = (data: string) => {
console.log('Listener 1 received:', data);
};
const listener2 = (data: string) => {
console.log('Listener 2 received:', data);
};
observer.subscribe(listener1);
observer.subscribe(listener2);
// Notify all observers
observer.notify('Hello, World!');
// Output:
// Listener 1 received: Hello, World!
// Listener 2 received: Hello, World!
```
### Working with Custom Types
```typescript
import { Observer } from '@mirawision/observer';
// Define a custom type for your events
interface UserEvent {
id: number;
name: string;
action: 'login' | 'logout';
}
// Create an observer for your custom type
const userObserver = new Observer<UserEvent>();
// Subscribe with type-safe listeners
userObserver.subscribe((event: UserEvent) => {
console.log(`User ${event.name} (ID: ${event.id}) performed ${event.action}`);
});
// Notify with type-safe data
userObserver.notify({
id: 123,
name: 'John Doe',
action: 'login'
});
// Output: User John Doe (ID: 123) performed login
```
### Managing Subscriptions
```typescript
import { Observer } from '@mirawision/observer';
const observer = new Observer<number>();
const listener = (data: number) => {
console.log('Received:', data);
};
// Subscribe
observer.subscribe(listener);
// Notify
observer.notify(42);
// Output: Received: 42
// Unsubscribe specific listener
observer.unsubscribe(listener);
// Notify again (no output since listener was removed)
observer.notify(100);
// Unsubscribe all listeners
observer.unsubscribeAll();
```
### Real-world Example: Event System
```typescript
import { Observer } from '@mirawision/observer';
// Define event types
interface AppEvent {
type: 'user-login' | 'user-logout' | 'data-update';
payload: any;
timestamp: Date;
}
// Create a global event bus
class EventBus {
private observer = new Observer<AppEvent>();
subscribe(listener: (event: AppEvent) => void) {
this.observer.subscribe(listener);
}
unsubscribe(listener: (event: AppEvent) => void) {
this.observer.unsubscribe(listener);
}
emit(event: AppEvent) {
this.observer.notify(event);
}
}
// Usage
const eventBus = new EventBus();
// Subscribe to events
eventBus.subscribe((event) => {
console.log(`[${event.timestamp.toISOString()}] ${event.type}:`, event.payload);
});
// Emit events
eventBus.emit({
type: 'user-login',
payload: { userId: 123, username: 'john' },
timestamp: new Date()
});
eventBus.emit({
type: 'data-update',
payload: { items: ['item1', 'item2'] },
timestamp: new Date()
});
```
### React Integration Example
```typescript
import React, { useEffect, useState } from 'react';
import { Observer } from '@mirawision/observer';
// Create a global observer for app state
const appStateObserver = new Observer<{ theme: 'light' | 'dark' }>();
function ThemeToggle() {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
useEffect(() => {
const handleThemeChange = (data: { theme: 'light' | 'dark' }) => {
setTheme(data.theme);
};
appStateObserver.subscribe(handleThemeChange);
// Cleanup on unmount
return () => {
appStateObserver.unsubscribe(handleThemeChange);
};
}, []);
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
appStateObserver.notify({ theme: newTheme });
};
return (
<button onClick={toggleTheme}>
Current theme: {theme}
</button>
);
}
```
## API Reference
### Observer<T>
A generic observer class that manages a collection of listeners for a specific data type.
#### Methods
- `subscribe(observer: ObserverListener<T>): void`
- Adds a listener to the observer
- The listener will be called whenever `notify()` is called
- `unsubscribe(observer: ObserverListener<T>): void`
- Removes a specific listener from the observer
- Useful for cleanup to prevent memory leaks
- `unsubscribeAll(): void`
- Removes all listeners from the observer
- Clears the entire observer collection
- `notify(data: T): void`
- Notifies all subscribed listeners with the provided data
- Calls each listener function with the data parameter
#### Type Definitions
```typescript
type ObserverListener<T> = (data: T) => void;
class Observer<T> {
// ... methods
}
```
## Contributing
Contributions are always welcome! Feel free to open issues or submit pull requests.
## License
This project is licensed under the MIT License.