我正在尝试使用union类型构建一个轻量级事件系统,我可以在其中侦听union中一种类型的事件。这是我到目前为止(不幸的是,它并没有真正使用类型):
class EventSystem {
events: { [key: string]: { (event: EventType) }[] };
constructor() {
this.events = {};
}
emit(key: string, event: EventType): void {
var arr = this.events[key];
for (let i = 0; i < arr.length; ++i) {
arr[i](event);
}
}
on(key: string, callback: (event: EventType) => void) {
if (key in this.events) {
this.events[key].push(callback);
} else {
this.events[key] = [callback];
}
}
}
interface EventA {
foo: Number
}
interface EventB {
bar: Number
baz: string
}
type EventType = EventA | EventB
const EventNames = {
EventA: 'EventA',
EventB: 'EventB'
}
let x = {foo: 2} as EventA;
let y = {
bar: 4,
baz: "test"
} as EventB;
let es = new EventSystem();
es.on(EventNames.EventA, function (a: EventA) {
console.log(a);
});
//Triggers the on above
es.emit(EventNames.EventA, x);
//Unfortunately, this also triggers the on above
es.emit(EventNames.EventA, y);
我真正想要的是这样的:
let es = new EventSystem<EventType>();
es.on<EventA>(function (a) {
//a is inferred to be EventA
console.log(a);
});
//Triggers the on above
es.emit(x);
//Will not trigger the on, since the type does not match
es.emit(y);
//Type error, since number is not in EventType
es.emit(4);
在Typescript中可以这样吗?如果没有,是否有比我正在做的更安全的方法?或者更好的方式来获得这种行为?
修改
目前,我正在做以下事情。它为EventSystem类添加了很多样板(我有数百种消息类型),并且在我看来也使api有点难看,但至少我得到类型安全。重复代码的数量让我觉得必须有更好的方法。
class EventSystem {
events: {[P in EventNames]: { (event: EventType) }[]} = {
'EventA': [],
'EventB': []
};
emitEventA(event: EventA): void {
this.events['EventA'].forEach((eventFunc) => eventFunc(event));
}
emitEventB(event: EventB): void {
this.events['EventB'].forEach((eventFunc) => eventFunc(event));
}
onEventA(callback: (event: EventA) => void) {
this.events['EventA'].push(callback);
}
onEventB(callback: (event: EventB) => void) {
this.events['EventB'].push(callback);
}
}
interface EventA {
foo: Number
}
interface EventB {
bar: Number
baz: string
}
type EventType = EventA | EventB
type EventNames = 'EventA' | 'EventB'
let x = { foo: 2 } as EventA;
let y = {
bar: 4,
baz: "test"
} as EventB;
let es = new EventSystem();
es.onEventA(function (a) {
console.log(a);
});
//Triggers the on above
es.emitEventA(x);
//Correctly caught now
es.emitEventA(y);
答案 0 :(得分:0)
是的,有可能。以下是一些适用于我的项目的示例代码:
class ProducerClass {
private config;
private logger;
constructor(config: Config, logger: Logger);
enqueue<T extends string, M extends object>(topic: T, message: M): Promise<boolean>;
connect(): void;
}
const producer = ProducerClass(config, logger);
type Topic = 'someTask' | 'someOtherTask';
interface Message {
objectId: number;
}
await producer.enqueue<Topic, Message>('someTask', { objectId: id });