我想弄清楚如何有效地將強類型事件添加到我的項目中,但仍然遇到奇怪的問題。理想情況下,我想能夠做這樣的事情:爲強類型事件添加定義
declare class EventEmitter<T> {
on<K extends keyof T>(event: K, fn: (...args: T[K]) => void, context?: any): void;
once<K extends keyof T>(event: K, fn: (...args: T[K]) => void, context?: any): void;
emit<K extends keyof T>(event: K, ...args: T[K]): boolean;
}
interface MyEvents {
'eventA': [string, number];
'eventB': [string, { prop: string, prop2: number }, (arg: string) => void];
}
class MyEmitter extends EventEmitter<MyEvents> {
// ...
}
const myEmitter = new MyEmitter();
myEmitter.on('eventA', (str, num) => {});
myEmitter.once('eventB', (str, obj, fn) => {});
myEmitter.emit('eventA', 'foo', 3);
第一個問題是,顯然元組是不是有效的類型參數休息儘管引擎蓋下類型元素的單純是陣列(我相信目前正在進行這項工作)。我想這很好,如果我放棄輸入emit
方法,並且使我的事件映射到函數類型而不是元組。這也會給一些額外的信息帶來好處。
declare class EventEmitter<T> {
on<K extends keyof T>(event: K, fn: T[K], context?: any): void;
once<K extends keyof T>(event: K, fn: T[K], context?: any): void;
}
interface MyEvents {
'eventA': (str: string, num: number) => void;
'eventB': (
str: string,
data: { prop: string, prop2: number },
fn: (arg: string) => void
) => void;
}
class MyEmitter extends EventEmitter<MyEvents> {
// ...
}
const myEmitter = new MyEmitter();
myEmitter.on('eventA', (str, num) => {});
myEmitter.once('eventB', (str, obj, fn) => {});
在這一點上,我很難過。智能感知可以推斷出on
或once
的正確簽名,但實際參數類型僅針對其回調參數最多的事件推斷,這使得沒有對我有意義。前幾天我打開an issue,但還沒有得到答覆。我不確定這實際上是一個錯誤,還是我忽略了一些東西。
與此同時,是否有任何有效的方法來做到這一點?我想過只是增加重載我發射器類這樣的(這裏EventEmitter
只是使用節點分型):
class MyEmitter extends EventEmitter {
on(event: 'eventA', fn: (str: string, num: number) => void);
on(event: 'eventB', fn: (
str: string,
data: { prop: string, prop2: number },
fn: (arg: string) => void
) => void);
}
然而,這需要我有一個實際的實施on
在我的課,如果我想要once
或emit
的類型我必須複製所有的事件定義。有更好的解決方案嗎?