event-emitter-typescript
v2.1.1
Published
Typesafe event emitter for browser and Node
Downloads
60
Readme
🦘 event-emitter-typescript
A minimal, type-safe event emitter library for browser and Node.js
⚛️ Comes with optional React bindings ⚛️
Links:
- Documentation: event-emitter.com
- NPM Package: npmjs.com/package/event-emitter-typescript
Installation:
With npm:
npm i event-emitter-typescript
With yarn:
yarn add event-emitter-typescript
Usage
Basic usage
import {EventEmitter} from "event-emitter-typescript";
const eventEmitter = new EventEmitter<{
"user:registered": { name: string; email: string; };
"otherEvent": { data: string; };
}>();
// Type-safe - inferred user type
const unsubscribe = eventEmitter.on("user:registered", async (user) => {
await userRepository.save(user);
});
// Type-safe
eventEmitter.emit("user:registered", { name: "John Doe", email: "[email protected]" });
// TypeScript error - email should be present
eventEmitter.emit("user:registered", { name: "John Doe" });
// Call unsubscribe function when we do not need to listen for "user:registered" anymore
unsubscribe();
React
Implementing clean code principles and Inversion of Control (IoC)
To ensure loose coupling, avoid using a global eventEmitter variable.
Instead, create an event emitter instance and pass it to the createProvider
function.
Then, use the event emitter from the created context.
/*
Let's assume we have the following project structure:
src/
- App.tsx
- emitter.ts
- index.tsx
*/
src/emitter.ts
import { EventEmitter } from "event-emitter-typescript";
import { createProvider } from "event-emitter-typescript/react"
// Create our own event map
type EventMap = {
"user:updated": {
id: number;
email: string;
name: string;
};
"article:created": {
id: number;
title: string;
body: string;
};
};
// Create a typed event emitter instance. Export it to use in not-react prat of the app
export const eventEmitter = new EventEmitter<EventMap>();
// Create a context provider and hooks to work with it in our React app
// useEvent and useEventEmitter are statically typed here
export const [EventEmitterContextProvider, { useEvent, useEventEmitter }] = createProvider(eventEmitter);
src/index.tsx
import React from "react";
import { createRoot } from "react-dom";
import { EventEmitterProvider } from "@/emitter";
import { App } from "@/App";
createRoot(document.getElementById('root')).render(
<EventEmitterProvider>
<App />
</EventEmitterProvider>
);
src/App.tsx
import React from "react";
import { useEvent, useEventEmitter } from "@/emitter";
export const App = () => {
const [articles, setArticles] = useState([]);
const eventEmitter = useEventEmitter();
// Article here is typed as { id: number; title: string; body: string; }
useEvent("article:added", (article) => {
setArticles([...articles, article])
});
return (
<main>
<button
onClick={() => {
// We can use useEventEmitter and useEvent from src/emitter in any child component
eventEmitter.emit("article:added", { id: 1, title: 'new article', body: 'hello world' });
}}
>
Add article
</button>
<h1>My blog</h1>
{articles.map(article => <Article key={article.id} {...article} />)}
</main>
);
};
API
Table of Contents
Base
EventEmitter
EventEmitter<Events> class.
Accepts custom event map as a generic param.
on
Subscribes an event handler to the event
Parameters
event
E Key of provided custom event mapsubscriber
function (data: Events[E]): void Event handler
Examples
// Type-safe
const unsubscribe = eventEmitter.on("user:registered", async (user) => {
await userRepository.save(user);
});
// Type-safe
eventEmitter.emit("user:registered", { name: "John Doe", email: "[email protected]" });
// Call unsubscribe fn when we do not need to listen for "user:registered" anymore
unsubscribe();
Returns function (): void
emit
Emits an event to the subscribers
Parameters
event
E Key of provided custom event maparg
Events[E] Event data
Examples
// Type-safe
eventEmitter.emit("user:registered", { name: "John Doe", email: "[email protected]" });
off
Unsubscribes an event handler from the event
Parameters
event
E Key of provided custom event mapsubscriber
function (data: Events[E]): void Event handler
Examples
eventEmitter.off("user:registered", registeredHandler);
once
Subscribes for a single event. Unsubscribes right after one event handled
Parameters
event
E Key of provided custom event mapsubscriber
function (data: Events[E]): void Event handler
Examples
eventEmitter.once("user:registered", registeredHandler);
eventEmitter.emit("user:registered", { name: "a", email: "b" });
eventEmitter.emit("user:registered", { name: "a", email: "b" });
// registeredHandler was called only 1 time
React
createProvider
Creates React context provider and hooks: useEvent, useEventEmitter
Parameters
eventEmitter
EventEmitter Event emitter to work with
Examples
import { EventEmitter } from "event-emitter-typescript";
import { createProvider } from "event-emitter-typescript/react";
const eventEmitter = new EventEmitter<{ "user:created": {id: number} }>();
// useEvent and useEvent emitter are statically typed here
export const [EventEmitterProvider, { useEvent, useEventEmitter }] = createProvider(eventEmitter);