Task
I’m building an utility with following interface:
interface F<M extends Record<string, Function>> {
(
listeners: M,
options: { filter: e => boolean }
): void
}
Special thing here is filter
option, which will receive events from all provided listeners.
I want type of e
parameter to depend on provided listeners:
f({
e1: (e: E1) => {}
}, {
filter: e => {} // <= `e` should be of type `E1`
})
f({
e1: (e: E1) => {},
e2: (e: E2) => {}
}, {
filter: e => {} // <= `e` should be of type `E1 | E2`
})
Solution
I found a way to do this:
interface F<T> {
<E extends keyof T>(
listeners: Pick<T, E>,
options: { filter: (e: Arg<T[E]>) => boolean }
): void
}
It does exactly what I want with parameter of filter
func, and it correctly applies constraints to listeners
, forbidding to add keys not defined in T
.
Problem
It’s just one little issue – typescript can’t hint available keys for listeners
object.
I.e., if I declare let f: F<{ e1: Function, e2: Function }>
and do f({ ... })
and ctrl+space – it shows a whole bunch of random stuff, instead of just e1
and e2
.
I understand that it’s expected behavior with this implementation. TS can’t know about available options, because, basically, it’s me who defines type of listeners
, TS can only test it then against constraint of keyof T
.
But is it possible, by any chance, to achieve typehints here? While not losing neither proper inference of parameter of filter
cb, nor keys validation of listeners
param?
I played around in a sandbox, yet all options I tried lack one or another feature I want.