Does TypeScript support events on classes?

I'm just wondering if it is possible to define custom events in TypeScript on my classes or interfaces?

How will it look like?

+43
typescript
Oct 14 '12 at 10:07
source share
6 answers

What about this simplified event to be used as a property? Stronger typification of the ownership class and lack of inheritance requirements:

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; } } 

used like 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); } 

Improvements?

The bottom line for this

+80
Feb 02 '13 at 2:14
source share

I think you are asking if a class instance can implement addEventListener () and dispatchEvent () as a DOM element. If the class is not a DOM node, you will need to write your own event bus. You would define an interface for a class that can post events, and then implement an interface in your classes. Here is a naive example:

 interface IEventDispatcher{ // maintain a list of listeners addEventListener(theEvent:string, theHandler:any); // remove a listener removeEventListener(theEvent:string, theHandler:any); // remove all listeners removeAllListeners(theEvent:string); // dispatch event to all listeners dispatchAll(theEvent:string); // send event to a handler dispatchEvent(theEvent:string, theHandler:any); } class EventDispatcher implement IEventDispatcher { private _eventHandlers = {}; // maintain a list of listeners public addEventListener(theEvent:string, theHandler:any) { this._eventHandlers[theEvent] = this._eventHandlers[theEvent] || []; this._eventHandlers[theEvent].push(theHandler); } // remove a listener removeEventListener(theEvent:string, theHandler:any) { // TODO } // remove all listeners removeAllListeners(theEvent:string) { // TODO } // dispatch event to all listeners dispatchAll(theEvent:string) { var theHandlers = this._eventHandlers[theEvent]; if(theHandlers) { for(var i = 0; i < theHandlers.length; i += 1) { dispatchEvent(theEvent, theHandlers[i]); } } } // send event to a handler dispatchEvent(theEvent:string, theHandler:any) { theHandler(theEvent); } } 
+9
Oct. 15 '12 at 23:54
source share

Strongly typed events for the TypeScript project (version 0.3 ) implements 3 types of events: IEvent<TSender, TArgs> , ISimpleEvent<TArgs> and ISignal . This makes it easy to use the right event for your project. It also hides the sending method from your event, as information should be hidden.

Event Types / Interfaces - Event Definitions:

 interface IEventHandler<TSender, TArgs> { (sender: TSender, args: TArgs): void } interface ISimpleEventHandler<TArgs> { (args: TArgs): void } interface ISignalHandler { (): void; } 

Example - This example shows how three types of events can be implemented using a ticking clock:

 class Clock { //implement events as private dispatchers: private _onTick = new SignalDispatcher(); private _onSequenceTick = new SimpleEventDispatcher<number>(); private _onClockTick = new EventDispatcher<Clock, number>(); private _ticks: number = 0; constructor(public name: string, timeout: number) { window.setInterval( () => { this.Tick(); }, timeout); } private Tick(): void { this._ticks += 1; //trigger event by calling the dispatch method and provide data this._onTick.dispatch(); this._onSequenceTick.dispatch(this._ticks); this._onClockTick.dispatch(this, this._ticks); } //expose the events through the interfaces - use the asEvent //method to prevent exposure of the dispatch method: public get onTick(): ISignal { return this._onTick.asEvent(); } public get onSequenceTick() : ISimpleEvent<number>{ return this._onSequenceTick.asEvent(); } public get onClockTick(): IEvent<Clock, number> { return this._onClockTick.asEvent(); } } 

Use . It can be used as follows:

 let clock = new Clock('Smu', 1000); //log the ticks to the console clock.onTick.subscribe(()=> console.log('Tick!')); //log the sequence parameter to the console clock.onSequenceTick.subscribe((s) => console.log(`Sequence: ${s}`)); //log the name of the clock and the tick argument to the console clock.onClockTick.subscribe((c, n) => console.log(`${c.name} ticked ${n} times.`)) 

More details here: About events, dispatchers and lists (general description of the system)

Textbooks
I have written several guides on this subject:

+7
Mar 27 '16 at 18:04
source share

You can use custom events in TypeScript. I'm not sure what you are trying to do, but here is an example:

 module Example { export class ClassWithEvents { public div: HTMLElement; constructor (id: string) { this.div = document.getElementById(id); // Create the event var evt = document.createEvent('Event'); evt.initEvent('customevent', true, true); // Create a listener for the event var listener = function (e: Event) { var element = <HTMLElement> e.target; element.innerHTML = 'hello'; } // Attach the listener to the event this.div.addEventListener('customevent', listener); // Trigger the event this.div.dispatchEvent(evt); } } } 

If you want to do something more specific, please let me know.

+2
Oct. 14
source share

This solution allows you to directly write parameters in a function call instead of having to wrap all your parameters in an object.

 interface ISubscription { (...args: any[]): void; } class PubSub<T extends ISubscription> { protected _subscribed : ISubscriptionItem[] = []; protected findSubscription(event : T) : ISubscriptionItem { this._subscribed.forEach( (item : ISubscriptionItem) =>{ if (item.func==event) return item; } ); return null; } public sub(applyObject : any,event : T) { var newItem = this.findSubscription(event); if (!newItem) { newItem = {object : applyObject, func : event }; this._subscribed.push(newItem); this.doChangedEvent(); } } public unsub(event : T) { for ( var i=this._subscribed.length-1 ; i>=0; i--) { if (this._subscribed[i].func==event) this._subscribed.splice(i,1); } this.doChangedEvent(); } protected doPub(...args: any[]) { this._subscribed.forEach((item : ISubscriptionItem)=> { item.func.apply(item.object, args); }) } public get pub() : T { var pubsub=this; var func= (...args: any[]) => { pubsub.doPub(args); } return <T>func; } public get pubAsync() : T { var pubsub=this; var func = (...args: any[]) => { setTimeout( () => { pubsub.doPub(args); }); } return <T>func; } public get count() : number { return this._subscribed.length } } 

Using:

 interface ITestEvent { (test : string): void; } var onTestEvent = new PubSub<ITestEvent>(); //subscribe to the event onTestEvent.sub(monitor,(test : string) => {alert("called:"+test)}); //call the event onTestEvent.pub("test1"); 
0
Aug 17 '15 at 15:15
source share

If you want to get an intelli-sense type check using a standard emitter pattern, you can do the following:

 type DataEventType = "data"; type ErrorEventType = "error"; declare interface IDataStore<TResponse> extends Emitter { on(name: DataEventType, handler : (data: TResponse) => void); on(name: ErrorEventType, handler: (error: any) => void); } 
-one
Mar 17 '16 at 14:42
source share



All Articles