Strongly typed event handlers in TypeScript (Part 1)

As a C# programming I have a lot of interest in the TypeScript project. Lately I've been playing around with it to look what it can do. I found myself in need of some event handling, so I decided to build something that looks like the event handling .Net gives you. It grew into Strongly Typed Events for TypeScript. This tutorial is part of a series.

2018-02: we've updated to a new version of the project. The article matches the latest version. Get the latest version by running:  npm install strongly-typed-events --save

The IEvent<TSender, TArgs>

An event is defined as a pair of sender and event arguments. It's leveraging generics to make them strongly typed. Note: the actual interface in the project is a little bit more complex.

/** Models an event with a generic sender and generic arguments */
interface IEvent<TSender, TArgs> {

    subscribe(fn: (sender: TSender, args: TArgs) => void): void;

    unsubscribe(fn: (sender: TSender, args: TArgs) => void): void;
}

Example implementation: a pulse generator

Let's create a pulse generator that will trigger an event based on the given the frequency in Hertz. I'm using the EventDispatcher from the package:

/** Models an event with a generic sender and generic arguments */
interface IEvent<TSender, TArgs> {

    subscribe(fn: (sender: TSender, args: TArgs) => void): void;

    unsubscribe(fn: (sender: TSender, args: TArgs) => void): void;
}

Now let's subscribe to the event and beep each time we receive a pulse.

var generator = new PulseGenerator(1);

//subscribe on the onPulse event
generator.onPulsate.subscribe((p, hz) => {

    //play beep:
    var snd = new Audio("data:audio/wav;base64,UklGRkYDAABXQVZFZm10IBAAAAABAAEAQB8AAIA+AAACABAAZGF0YSIDAAAAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAAAzNRVWFVYzNQAAzcrrqeupzcoAADM1FVYVVjM1AADNyuup66nNygAAMzUVVhVWMzUAAM3K66nrqc3KAACJNO5T2lKKMgAAys50sYeyydAAAOMtK0kYSOQrAABx1Ta8Sr1v1wAAPCdoPlU9PiUAABfc+cYMyBbeAACWIKYzkjKXHgAAveK70c/SvOQAAO8Z4yjQJ/EXAABk6X7ckd1j6wAASRMhHg0dShEAAArwQedU6AnyAACjDF4TSxKkCgAAsfYD8hfzr/gAAPwFnAiIB/0DAABX/cb82f1W/wAA");
    snd.play();
    
});

//change frequency
setTimeout(function () {
    generator.frequencyInHz = 2;
}, 3000);

More

Check out the following:

  1. Joshua Smith says:

    I like the idea of strongly typed events (coming from C# myself) but one main purpose of events is decoupling (which .NET never cared about). So the main flaw of this library/examples I see is that you have the listener to subscribe to the source of the event.

    1. Listeners should be able to subscribe to the event (without knowing anything about the source)

    (because)
    2. Different sources should be able to raise the same event.

    (I guess this is somewhat achievable if the EventDispatcher becomes global rather than part of the source though your examples don’t demonstrate this)

    Long story short this lib seems like a simulation of ASP.NET events. For actual application my recommendation would be to take from .NET only the good part (leave the .NET flaws with .NET ;) )

    1. Kees C. Bakker says:

      I agree. But it would be important to have some sort of way of detecting the source of the event. How would we distinguish between events? Later versions of the library have different dispatchers (like signals and simple events that only have data).

expand_less