2017-04-14 73 views
0

我試圖建立工會使用的類型,在那裏我可以監聽來自於工會一類的事件一個輕量級的事件系統。這裏是我到目前爲止(不幸的是,它並沒有真正利用類型):類型安全事件處理聯合類型

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

是這樣的可能的打字稿?如果沒有,有沒有比我在做什麼更類型安全的方法嗎?或者更好的方式來獲得這種類型的行爲?

編輯:

現在,我做以下。它增加了很多的樣板到的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

是的,這是可能的。這裏是我的項目中的一些示例代碼:

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

爲什麼? '接口消息{}'正是這樣做的。 –

+0

對不起,你說得對。我會刪除我的評論。 –