Reputation: 20564
Is it possible to make Typescript figure out the types of the arguments of this callback based on an interface?
export interface MiddlewareEvent {
onNewAccount: (accountId: string, timestamp: number) => void,
onAccountDelete: (accountId:string, timestamp:number)=>void,
}
const middlewareMap: Map<keyof MiddlewareEvent,((...arg: any) => void )[]> = new Map();
function registerMiddleWare(
eventId: keyof MiddlewareEvent,
middleware: ((...arg: any) => void)
) {
const existing = middlewareMap.get(eventId);
if (!existing?.length) {
middlewareMap.set(eventId, [middleware]);
} else {
existing.push(middleware);
}
}
registerMiddleWare(`onNewAccount`, (accountId: number, datetime: string) => {
console.log(`Wait, Typescript should have prevented this`)
console.log(`account Id is string not number`)
console.log(`datetime has been changed to timestamp and is now a number`)
})
The idea is to just pass the property of the interface as a string (or enum ? ) to a function as first parameter and Typescript should figure out of the types of the argument of the callback which is the second parameter by looking that key in the interface.
This won`t require the user to manually pass a generic type argument everytime.
Upvotes: 0
Views: 387
Reputation: 187134
Sure, you just need an inferred generic function. Let it infer the eventId
being passed in, and then drill into MiddlewareEvent
based on that key.
function registerMiddleWare<EventName extends keyof MiddlewareEvent>(
eventId: EventName,
middleware: MiddlewareEvent[EventName]
) { /* ... */ }
registerMiddleWare(`onNewAccount`, (accountId: number, datetime: string) => {})
// Argument of type
// '(accountId: number, datetime: string) => void'
// is not assignable to parameter of type
// '(accountId: string, timestamp: number) => void'
Upvotes: 1