2.1.1 • Published 12 months ago

event-emitter-typescript v2.1.1

Weekly downloads
-
License
ISC
Repository
github
Last release
12 months ago

🦘 event-emitter-typescript

A minimal, type-safe event emitter library for browser and Node.js

⚛️ Comes with optional React bindings ⚛️

Size Gzip Static Badge NPM Downloads NPM Version

Links:

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: "johndoe@example.org" });

// 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 map
  • subscriber 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: "johndoe@example.org" });

// 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 map
  • arg Events[E] Event data
Examples
// Type-safe
eventEmitter.emit("user:registered", { name: "John Doe", email: "johndoe@example.org" });
off

Unsubscribes an event handler from the event

Parameters
  • event E Key of provided custom event map
  • subscriber 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 map
  • subscriber 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);
2.1.1

12 months ago

2.1.0

12 months ago

2.0.1

1 year ago

2.0.0

1 year ago

1.0.0

1 year ago