I want to create a function addEventListener
This function has two arguments, the event
and the listener
.
I have some specific events: ex. onScroll
, onClick
, onDoubleClick
.
Depending on the event
I want to have a separate signature / type for the listener
argument.
So if I start typing:
addEventListener('onClick', (param: OnClickType) => // here I want to resolve a certain listener type )
// or
addEventListener('onScroll', (param: OnScrollType) => // here I want to resolve a certain listener type )
Is this possible in typescript?
[EDIT]
Something like this:
[EDIT2]
export type OnClick = (event: 'onclick', listener: (x: number) => void) => void
export type OnScroll = (event: 'onscroll', listener: (x: string) => void) => void
export type EventListener = OnClick | OnScroll;
const addEventListener: EventListener = (ev, ls) => {
console.log(ev, ls);
return;
}
addEventListener('onclick', )
What I want is to infer the type of the second argument of the function ( listener
) depending on the value of the first argument ( event
).
If you have just a few hardcoded function types like OnClick
and OnScroll
:
type OnClick = (event: 'onclick', listener: (x: number) => void) => void
type OnScroll = (event: 'onscroll', listener: (x: string) => void) => void
and you want to say that an EventListener
can behave like all of them, you can manually rewrite both call signatures into a single, overloaded function type:
type EventListener = {
(event: 'onclick', listener: (x: number) => void): void;
(event: 'onscroll', listener: (x: string) => void): void;
}
const addEventListener: EventListener = (ev, ls) => {
console.log(ev, ls);
return;
}
addEventListener('onclick', x => console.log(x.toFixed(2))); // okay
addEventListener('onscroll', x => console.log(x.toUpperCase())); // okay
Equivalently, you can just write EventListener
as the intersection of the existing function types:
type EventListener = OnClick & OnScroll;
This puts both call signatures into the same type, as an overloaded function type with the OnClick
signature first and the OnScroll
signature second. So when you call an EventListener
the compiler will try to resolve the OnClick
call signature first, and then fall back to OnScroll
if that fails. Since "onclick"
and "onscroll"
are mutually exclusives, the order doesn't really matter here. But there are cases where order of call signature resolution does matter, and then a type F1 & F2
will behave differently from F2 & F1
(which might be surprising since intersections are conceptually unordered).
If you have a bunch of different event names and payload types and you don't want to manually write out one call signature for each such pair, you can forgo multi-call signature overloads in favor of a single generic function:
interface EventMap {
onclick: number;
onscroll: string;
}
type EventListener = <E extends keyof EventMap>(
event: E, listener: (x: EventMap[E]) => void
) => void;
This behaves similarly (the prior implementation of and calls to addEventListener()
still work), but now you can just add a new line to EventMap
for each new event name / payload type pair.
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.