Looking for a way to define a function in TypeScript that will accept, as one of it's arguments, a function that may be of different signatures
const foo = (a: string, b: number) => {
//do something
}
const bar = (a: number, b: string, c: boolean) => {
//do something
}
const myDynamicFunction = (
str: string,
// I tried this, but no dice
method: ((a: string, b: number) => void) | ((a: number, b: string, c: boolean) => void),
num: number,
bool?: boolean
) => {
if (bool) {
method(num, str, bool)
} else {
method(str, num)
}
}
myDynamicFunction(
'string', foo, 5
)
myDynamicFunction(
'string', bar, 5, true
)
I tried going down the "function overloads" rabbit hole, but that just left me where I started w/ essentially the same error of unexpected number of arguments.
CodePudding user response:
I think you'd have to cast your method, because TypeScript cant figure this one out:
if (bool) {
(method as (a: number, b: string, c: boolean) => void)(num, str, bool)
} else {
(method as (a: number, b: string) => void)(num, str)
}
CodePudding user response:
There were some subtleties that I couldn't get my head around at first, but breaking it down finally got me there. Typescript seems to have some difficulty disambiguating parameter types without first defining discreet type aliases.
We need to use a type predicate to determine, based on the value of bool
, whether we are dealing with a call to a BAR like function.
When we do that, we still haven't narrowed the type of bool
to be specifically boolean (another predicate would do the job also), but we know that's the case so we can use the !
non-null assertion to allow it to be passed to a method that requires boolean
.
type FOO = (a: string, b: number) => void
type BAR = (a: number, b: string, c: boolean) => void
function isBAR(method: any, bool: boolean | undefined): method is BAR {
return typeof method === 'function' && typeof bool !== undefined
}
const foo = (a: string, b: number) => {
//do something
}
const bar = (a: number, b: string, c: boolean) => {
//do something
}
const myDynamicFunction = (
str: string,
method: FOO | BAR,
num: number,
bool?: boolean
) => {
isBAR(method, bool) ? method(num, str, bool!) : method(str, num)
}
myDynamicFunction('string', foo, 5)
myDynamicFunction('string', bar, 5, true)