I'm trying to implement an event emitter. The code is very simple.
Right now tsc
thinks that the event type in eventHandler
is 'ErrorEvent' | 'MessageEvent'
'ErrorEvent' | 'MessageEvent'
. This is the problem and I want tsc
to narrow the types to the correct one (depending on eventName
passed to the on
function).
Can it be done?
Definitions
interface Event {
code: string;
}
interface ErrorEvent extends Event {
xxx: number;
}
interface MessageEvent extends Event {
yyy: number;
}
interface Events {
error: ErrorEvent,
message: MessageEvent
}
type EventHandler = (event: Events[keyof Events]) => void;
TS CODE
function on (eventName: keyof Events, eventHandler: EventHandler) {
console.log(eventName)
}
on('message', (event) => { // ErrorEvent | MessageEvent
console.log(event)
console.log(event.code)
console.log(event.xxx) // Property 'xxx' does not exist on type 'ErrorEvent | MessageEvent'.
console.log(event.yyy) // Property 'yyy' does not exist on type 'ErrorEvent | MessageEvent'.
})
First you have to get rid of EventHandler as a union type:
type EventHandler<K extends EventKeys> = (event: Events[K]) => void
That way you get a concrete type for you handler for each concrete K
. And then you make sure second argument type of the on
function depends on the first one. Thus you have to introduce a type parameter to you function to get types in line:
function on <K extends EventKeys>(eventName: K, eventHandler: EventHandler<K>): void {}
I believe this should do:
interface Event {
code: string;
}
interface ErrorEvent extends Event {
xxx: number;
}
interface MessageEvent extends Event {
yyy: number;
}
interface Events {
error: ErrorEvent,
message: MessageEvent
}
type EventKeys = keyof Events
type EventHandler<K extends EventKeys> = (event: Events[K]) => void;
function on <K extends EventKeys>(eventName: K, eventHandler: EventHandler<K>): void {
console.log(eventName)
}
on('message', (event) => {
console.log(event)
console.log(event.code)
console.log(event.xxx) // Property 'xxx' does not exist on type 'MessageEvent<any>'.
console.log(event.yyy)
})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.