-
-
Save JasonKleban/50cee44960c225ac1993c922563aa540 to your computer and use it in GitHub Desktop.
interface ILiteEvent<T> { | |
on(handler: { (data?: T): void }) : void; | |
off(handler: { (data?: T): void }) : void; | |
} | |
class LiteEvent<T> implements ILiteEvent<T> { | |
private handlers: { (data?: T): void; }[] = []; | |
public on(handler: { (data?: T): void }) : void { | |
this.handlers.push(handler); | |
} | |
public off(handler: { (data?: T): void }) : void { | |
this.handlers = this.handlers.filter(h => h !== handler); | |
} | |
public trigger(data?: T) { | |
this.handlers.slice(0).forEach(h => h(data)); | |
} | |
public expose() : ILiteEvent<T> { | |
return this; | |
} | |
} |
class Security{ | |
private readonly onLogin = new LiteEvent<string>(); | |
private readonly onLogout = new LiteEvent<void>(); | |
public get LoggedIn() { return this.onLogin.expose(); } | |
public get LoggedOut() { return this.onLogout.expose(); } | |
// ... onLogin.trigger('bob'); | |
} | |
function Init() { | |
var security = new Security(); | |
var loggedOut = () => { /* ... */ } | |
security.LoggedIn.on((username?) => { /* ... */ }); | |
security.LoggedOut.on(loggedOut); | |
// ... | |
security.LoggedOut.off(loggedOut); | |
} |
Made a stricter version here, getting rid of optionality of data?: T
in various signatures without impacting the case where T
is void
and should overall require no data parameter: https://gist.github.com/JasonKleban/924babb9c56d697c2d2a8f6f604eb3d4. I didn't want to revise this version because that version might turn out to have some negative qualities.
This was super helpful Jason, thank you! I do have one question: why do you use this.handlers.slice(0).forEach instead of just this.handlers.forEach?
@maucaro in case one of the earlier handlers modifies the handlers array in the handling of a particular event. It's just the saner general approach, but I guess you can adjust this for your situation.
What is the point of having it private, then having an expose
method which returns the instance? Why not make it public from the beginning?
Thank you for this!
The way functions are typed are confusing to me, plus the repeated type definitions:
Here is my take on it, dropping expose(can be added back in for those who need it):
type THandler<T> = (data: T) => void;
interface ILiteEvent<T> {
on(handler: THandler<T>): void;
off(handler: THandler<T>): void;
}
export class LiteEvent<T> implements ILiteEvent<T> {
private handlers = Array<THandler<T>>();
public on(handler: THandler<T>): void {
this.handlers.push(handler);
}
public off(handler: THandler<T>): void {
this.handlers = this.handlers.filter((h) => h !== handler);
}
public trigger(data: T) {
this.handlers.slice(0).forEach((h) => h(data));
}
}
What is the point of having it private, then having an
expose
method which returns the instance? Why not make it public from the beginning?
It was an effort to discourage it from being written to. There are probably better ways these days if such control is needed.
Thanks!