在扩展EventEmitter的TypeScript类中声明事件

时间:2016-08-25 10:30:02

标签: node.js typescript

我有一个可以发出事件EventEmitter的类hello。如何使用特定事件名称和侦听器签名声明on方法?

class MyClass extends events.EventEmitter {

  emitHello(name: string): void {
    this.emit('hello', name);
  }

  // compile error on below line
  on(event: 'hello', listener: (name: string) => void): this;
}

6 个答案:

答案 0 :(得分:22)

最有效的方法是使用declare

declare interface MyClass {
    on(event: 'hello', listener: (name: string) => void): this;
    on(event: string, listener: Function): this;
}

class MyClass extends events.EventEmitter {
    emitHello(name: string): void {
        this.emit('hello', name);
    }
} 

答案 1 :(得分:14)

扩展@SergeyK的答案,这样您就可以在emiton函数上进行类型检查和完成,而无需重复事件类型。

  1. 为每种事件类型定义事件侦听器签名:
interface MyClassEvents {
  'add': (el: string, wasNew: boolean) => void;
  'delete': (changedCount: number) => void;
}
  1. 基于EventListeners(MyClass)函数签名为MyClassEvents构造类型的声明接口:
declare interface MyClass {
  on<U extends keyof MyClassEvents>(
    event: U, listener: MyClassEvents[U]
  ): this;

  emit<U extends keyof MyClassEvents>(
    event: U, ...args: Parameters<MyClassEvents[U]>
  ): boolean;
}
  1. 只需定义您的类即可扩展EventEmitter
class MyClass extends EventEmitter {
  constructor() {
    super();
  }
}

现在,您将获得onemit函数的类型检查:

enter image description here

enter image description here

不幸的是,您只能对这两个函数进行完成和类型检查(除非您在MyClass接口中定义了更多函数)。

要获取更多通用解决方案,可以使用this package注意:,它不会增加运行时开销。

import { TypedEmitter } from 'tiny-typed-emitter';

interface MyClassEvents {
  'add': (el: string, wasNew: boolean) => void;
  'delete': (changedCount: number) => void;
}

class MyClass extends TypedEmitter<MyClassEvents> {
  constructor() {
    super();
  }
}

答案 2 :(得分:2)

只需将自己连接到on('hello'例如:

class MyClass extends events.EventEmitter {

  emitHello(name: string): void {
    this.emit('hello', name);
  }

  on(listener: (name: string) => void){
    return this.on('hello',listener);
  } 
}

答案 3 :(得分:1)

您可以为此使用typed event emitter package

例如:

<script>
function calculateDiff(){
  var FromYear = parseInt(document.getElementById("FromYear").value);
  var FromMonth = parseInt(document.getElementById("FromMonth").value);
  var FromDay = parseInt(document.getElementById("FromDay").value);


  //current date
  var today = new Date();
  var ToYear = today.getFullYear();
  var ToMonth = today.getMonth() + 1;
  var ToDay = today.getDay()
  var years, months, days;

  //months
  months = ToMonth - FromMonth;
  if(ToDay < FromDay) {
    months = months -1;
  }


  //years
  years = ToYear - FromYear;
  if(ToMonth < FromMonth) {
    years = years - 1;
    months = months + 12;
  }

  //days
  days = Math.floor(31 - (FromYear + years, FromMonth + months - 1, FromDay));

  //answer order
  var answer = years + " years, " + months + " months, and " + days + " days.";

  //post answer
  document.getElementById("result").textContent =  answer;
  return {years: years, months: months, days: days};
}
</script>



   <table>
        <tbody>
        <tr class="header">
          <th>&nbsp;</th>
          <th>Year</th>
          <th>Month</th>
          <th>Day</th>
        </tr>
        <tr>
       <th>Birth Date</th>
          <td><input  id="FromYear"  placeholder="YYYY" value=""></td>
          <td><input  id="FromMonth" placeholder="MM" value=""></td>
          <td><input  id="FromDay"   placeholder="DD" value=""></td>
        </tr>

        <tr>
          <th colspan="4">
            <button id="calculateDiff" onclick="calculateDiff()">Calculate</button>
          </th>
        </tr>
        <tr colspan="4">
          <th>You are <div id="result"></div></th>
      </tr>
      </tbody>
    </table>

此软件包还提供了接口和一些实用程序。

答案 4 :(得分:0)

这就是我能够弄清楚的。用泛型覆盖默认功能!

interface IEmissions {
  connect: () => void
  test: (property: string) => void
}

class MyClass extends events.EventEmitter {
  private _untypedOn = this.on
  private _untypedEmit = this.emit
  public on = <K extends keyof IEmissions>(event: K, listener: IEmissions[K]): this => this._untypedOn(event, listener)
  public emit = <K extends keyof IEmissions>(event: K, ...args: Parameters<IEmissions[K]>): boolean => this._untypedEmit(event, ...args)

  this.emit('test', 'Testing') // This will be typed for you!
}

// Example:
const inst = new MyClass()
inst.on('test', info => console.log(info)) // This will be typed!

答案 5 :(得分:0)

the official typing package 使用 events library

npm install events @types/events