🧊

TypeScriptでEventEmitterのイベントに型をつけたい

毎回なぜか忘れて毎回調べてるので・・。

いろんなパターンがあるはず。

d.tsを手書きする場合

既存のコードがJavaScriptで完成していて、TypeScriptで書き直せない場合。

こんな風に`d.ts`を手書きすればいい。

/// <reference types="node" />
import { EventEmitter } from "events";

declare class Foo extends EventEmitter {
  // ...
  
  on(event: "open", listener: (id: string) => void): this;
  on(event: "close", listener: () => void): this;
  on(event: "error", listener: (err: Error) => void): this;
  on(event: string, listener: Function): this;

  once(event: "open", listener: (id: string) => void): this;
  once(event: "close", listener: () => void): this;
  once(event: "error", listener: (err: Error) => void): this;
  once(event: string, listener: Function): this;
}

export default Foo;


最後の行にフォールバックの雑なやつを追加するのが重要。

これらの定義をサボると、ぜんぶ`any`ないつものやつに自動的になる。
普通に`tsc`とかでビルドしたときもそうなる。

型を上書きして使う

GitHub - bterlson/strict-event-emitter-types: A type-only library for strongly typing any event emitter

このアプローチは割と見かける。
このライブラリだとこういうイメージで使う。

import StrictEventEmitter from 'strict-event-emitter-types';
import { EventEmitter } from 'events';

interface MyEvents {
  request: (request: Request, response: Response) => void;
  done: void;
}

const ee: StrictEventEmitter<EventEmitter, MyEvents> = new EventEmitter();

型を上書きするので、厳密には、元のコードと異なる可能性があるけど。

その他で見つけたやつ。

GitHub - andywer/typed-emitter: 🔩 Type-safe event emitter interface for TypeScript 3

そういうTSのモジュールを使う

もしくは作る。

Typesafe Event Emitter · TypeScript Deep Dive

APIが変わるので、そこを許容できるかどうかが焦点かな?

他にもなにかあったら教えてください!