TypeScript是否支持类上的事件?

Com*_*Cat 58 typescript

我只是想知道在TypeScript中你是否可以在类或接口上定义自定义事件?

这会是什么样的?

Jas*_*ban 100

这个简化事件如何用作财产?更强大的拥有类的类型,没有继承要求:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用:

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);
}
Run Code Online (Sandbox Code Playgroud)

改进?

这是一个要点

  • 建议做this.handlers.slice(0).forEach(h => h(data)); 而不是this.handlers.forEach(h => h(data)); (4认同)
  • 不错的解决方案。不要忘记让Event实现IEvent。 (2认同)
  • 为什么在`trigger`方法中检查`if(this.handlers)`?是不是总是如此? (2认同)
  • @Tarion - 是的,在我看来,这个检查可以省略.我假设我在.NET中调用之前需要对事件处理程序进行空值检查的方式进行了一些概念性结转,但我认为处理程序成员将始终为非null并且它将是一个数组.如果它不是数组,代码可能无论如何都会失败. (2认同)

Kee*_*ker 13

为打字稿强类型的活动项目(版本0.3)实现了3种类型的事件:IEvent<TSender, TArgs>,ISimpleEvent<TArgs>ISignal.这样可以更轻松地为项目使用正确的事件.它还隐藏了事件中的调度方法,因为良好的信息隐藏应该这样做.

事件类型/接口 - 事件的定义:

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

interface ISimpleEventHandler<TArgs> {
    (args: TArgs): void
}

interface ISignalHandler {
    (): void;
}
Run Code Online (Sandbox Code Playgroud)

示例 - 此示例显示如何使用滴答时钟实现3种类型的事件:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法 - 可以像这样使用:

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.`))
Run Code Online (Sandbox Code Playgroud)

在此处阅读更多内容:关于事件,调度员和列表(系统的一般说明)

教程
我已经写了一些关于这个主题的教程:


Ezw*_*ard 11

我想你是在问一个类实例是否可以像DOM元素一样实现addEventListener()和dispatchEvent().如果该类不是DOM节点,那么您必须编写自己的事件总线.您可以为可以发布事件的类定义接口,然后在类中实现接口.这是一个天真的例子;

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);
  }
}
Run Code Online (Sandbox Code Playgroud)