Extending Global Event System with Typescript Generics
Tags: typescript, javascript, eventdriven, webdev
Published: 2022-08-04 11:06:00

## Intro

[In the first part](https://dev.to/nicksettler/build-a-global-event-system-with-typescript-4f2h) we have gone through creation of the initial Event System. It allowed to track events happening anywhere in the code and trigger handlers for these events.

Anyway, the events currently must be predefined in the source code of the Event System. Also there is no event buffering, which means some code that has to process older events would not be able to retrieve them.

## Undoing Singleton Pattern

Due to impossibility to pass and store types to Event System made using Singleton pattern, it is necessary to remove this pattern. So this post expects working with code without private constructor, `getInstance` method and `instance` field of the Event System class.

After implementing this part, the Event System should always be initialized and stored in the code as a separate module.

## Custom Event Types

The current implementation allows to set predefined list of events that can be tracked via the Events System. Using such implementation as a library will not allow third party developers to extend this list according to their own needs. Also such lack makes code hard to refactor.

To fix this issue we can use the power of Typescript with generics, which will make third party customisation easier.

### Types and Interfaces Refactoring

Firstly, it is necessary to update type definitions including Event System class types.

Event System is expected to work with object-like types, in which key is a name of the event and value is a function that will be triggered when the event happens. So we can refactor our types to accept this kind of variables using TypeScript generics.

{% embed https://gist.github.com/NickSettler/d4c0c712adc9619feb30f71b176ba2e7.js %}

Using this refactoring makes it possible to pass a type containing key-value pairs of events’ names and their handlers. Such refactoring will be useful while adding generics to the Event System class methods.

### Class Methods Refactoring

To make Event System class methods work with events type passed via constructor, it is necessary to pass a type containing event’s names that will be handled.

{% embed https://gist.github.com/NickSettler/3216808d6e361ab07248af7741b199c9.js %}

After this update it will be possible to present the event name via generic while calling the function. Anyway, passing event name via generic is not necessary, because it is also passed as a function parameter, so it will be bound to generic key and this will ensure type safety while passing handler function or its parameters.

## Events Buffering

Events buffering can be useful when some of the Subscribers attach to an event too late when the event has already been triggered. This missed event trigger may be important for the Subscriber, but in the current implementation it is unable to get it afterwards.

Events buffering implementation will store the few last events. If the subscriber will attach later, he will receive the last few events and will have the possibility to handle them.

To implement this feature is necessary to install third party lib [Mnemonist](https://www.npmjs.com/package/mnemonist), which has functionality of fixed length buffers. The last item is deleted when there is a new item in such kind of buffer. This is useful to prevent storing all events, which can potentially fill a lot of memory even if they will not be needed anymore.

### Buffer Typing

The Event System should have availability to configure buffer behavior. For this purpose it is reasonable to introduce a few more types. The current buffer implementation assumes setting buffer direction from the following (First-In-First-Out or Last-In-First-Out) and buffer size.

{% embed https://gist.github.com/NickSettler/a6d0cfdb7098fc8f2be77c8f1988505c.js %}

### Event System Class Buffer Introduce

To setup buffer configuration it is required to pass buffer setup options via Event System constructor parameters. These parameters should be also made optional, so the Event System can be easier used as a library by third party developers.

The Mneonist data structure called `CircularBuffer` will be used to store a particular number of the last events. It will make sure that the number of events stored in the array is always constant.

{% embed https://gist.github.com/NickSettler/3c0d2de0bb37c050ab6d9b56318376a2.js %}

### Buffer Processing Logic

To store past events and trigger their handlers from new subscribers, it is necessary to update Event System methods.

`subscribe` method should check if there are any events in the buffer, in which a new subscriber is interested.

`notify` method should store all the events it receives in the buffer, to make their processing available for the subscribe method.

{% embed https://gist.github.com/NickSettler/84d5abf845e926813c4c8128f434a275.js %}

## Usage

Currently implemented logic makes it possible to initialize the Event System in a separate module and use it anywhere in the code. TypeScript with generics provides availability to set custom event types and ensures event handlers and arguments are passed with required data types. Events buffering affords events to be buffered and available for late subscribers.

> Github Repository: https://github.com/NickSettler/events-system