Edited at

自作Eventクラスに入力補完を適用させる


はじめに

TypeScript を使って、Node.jsのアプリケーションを開発しているときに、 入力補完 は活用していることでしょう。

この記事は、 引数が特定の条件である場合の入力補完を効かせる方法 を、 EventEmitter の拡張を題材として執筆しました。


コーディング

作成したコードは walk8243/TypeScript-EventEmitter にあります。

目的の 引数が特定の条件である場合の入力補完を効かせる方法 を実現するために重要となる技術は、 オーバーロード です。

ということで、オーバーロードについて書いていきます。


オーバーロード

詳しく知りたい方は、 TypeScript Deep Dive をご一読ください。

まず、普通にクラスを作成してみます。

class Power {

get(type: string, index: number) {
if(type == 'square') {
return index ^ 2;
} else {
throw new Error('type is `square` only.');
}
}
}

次に、これにオーバーロードしてみます。

class Power {

get(type: 'square', index: number): number;
get(type: string, index: number) {
if(type == 'square') {
return index ^ 2;
} else {
throw new Error('type is `square` only.');
}
}
}

このようにすることで、入力補完として第一引数に square が表示されるようになります。

また、次のように書くこともできます。

class Power {

get(type: 'square', index: number) {
if(type == 'square') {
return index ^ 2;
} else {
throw new Error('type is `square` only.');
}
}
}

オーバーロードするときのポイントとしては、必ず 処理を行う関数・メソッドを書くこと です。

例え、クラスで親クラスのメソッドをそのまま使う場合であっても、メソッドを書く必要があります。

次に実際にEventEmitterを継承したクラスでもって試してみたいと思います。


EventEmitterの継承

イベントとして、 keyboard, enter, escape, mouse の4つ作成しました。

import { EventEmitter } from 'events';

export class Event extends EventEmitter {
on(event: 'keyboard', listener: () => void): this; // listenerに引数無しのパターンを作成
// on(event: 'keyboard', listener: () => void): this; // すべての引数が同じパターンを記述することはできない
on(event: 'enter' | 'escape', listener: () => void): this; // listenerの引数のパターンが同じなのでまとめる
on(event: 'mouse', listener: (mouseX: number, mouseY: number) => void): this; // listenerに引数を追加
on(event: string, listener: (...args: any[]) => void) {
return super.on(event, listener); // 継承元を呼び出すだけでも処理を書く
}

emit(event: 'keyboard' | 'enter' | 'escape'): boolean; // 引数のパターンが同じなのでまとめる
emit(event: 'mouse', x: number, y: number): boolean; // 引数のパターンが違うので分ける
emit(event: string, ...args: any[]) {
return super.emit(event, ...args); // 処理を書く
}
}

これで以下のように入力補完を使うことができるようになりました。




おわりに

基本的に入力補完の効くエディタで開発をしていることと思います。

複数人で開発している場合、誰かが開発したコードを違う人が使うようなケースがあることと思います。

そのような場合、ドキュメントだったり口頭だったりで使い方を伝えてもいいですが、簡単な部分に関しては入力補完で事足りることでしょう。

また、TypeScriptの型定義は、入力補完だけでなく、コンパイルにチェックしてくれるので、デプロイ前にエラーを発見することにも繋がります。

積極的に型定義を行っていきましょう!


オーバーロードのまとめ

型定義をしていく上で、オーバーロードを使う機会は出てくると思うので、最後に使い方をまとめておきます。


  1. 必ず処理を書く。

  2. 型を詳細化するようにオーバーロードする

  3. 全く同じ引数の型パターンでは記述できない