typescript - Typesafe Event Handlers for Union Type -


i trying build lightweight event system using union types, can listen events 1 type in union. here have far (unfortunately, not utilize types):

class eventsystem {     events: { [key: string]: { (event: eventtype) }[] };      constructor() {         this.events = {};     }      emit(key: string, event: eventtype): void {         var arr = this.events[key];         (let = 0; < 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} eventa; let y = {     bar: 4,     baz: "test" } eventb;   let es = new eventsystem();  es.on(eventnames.eventa, function (a: eventa) {     console.log(a); });  //triggers on above es.emit(eventnames.eventa, x);  //unfortunately, triggers on above es.emit(eventnames.eventa, y); 

what want this:

let es = new eventsystem<eventtype>();  es.on<eventa>(function (a) {     //a inferred eventa     console.log(a); });  //triggers on above es.emit(x);  //will not trigger on, since type not match es.emit(y);  //type error, since number not in eventtype es.emit(4); 

is possible in typescript? if not, there more typesafe approach doing? or better way in general type of behavior?

edit:

for now, doing following. adds lot of boilerplate eventsystem class (i have hundreds of message types), , makes api little ugly in opinion, @ least type safety. amount of duplicated code makes me think there must better way.

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 } eventa; let y = {     bar: 4,     baz: "test" } eventb;   let es = new eventsystem();  es.oneventa(function (a) {     console.log(a); });  //triggers on above es.emiteventa(x);  //correctly caught es.emiteventa(y); 

yes, possible. here example code works in project:

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 }); 

Comments

Popular posts from this blog

php - Permission denied. Laravel linux server -

google bigquery - Delta between query execution time and Java query call to finish -

python - Pandas two dataframes multiplication? -