Reputation: 27
I have a function that accepts as an argument another function. The argument is an union type of functions that also may have or may have not arguments.
type innerFn = () => void | (arg: string) => void | (arg: number) => void | (arg: {}) => void
function mainFn (innerFn: InnerFnType) {
function run(arg?: *any*) {
innerFn()
}
return run
}
I want to know if the run argument can be inherited based on the function that is passed to mainFn.
The use case is:
const concreteInnerFn: InnerFnType = (arg: string) {
do something
}
const run = mainFn(concreteInnerFn)
run("hello") // OK
run(25) // ERROR
run({hello: true}) // ERROR
ie if I use (arg: string) => void
as the innerFn, when I try to use run()
it should ask for an argument of type string.
Hope its clear enough
Upvotes: 1
Views: 514
Reputation: 33061
You can do it:
type InnerFn =
| (() => void)
| ((arg: string) => void)
| ((arg: number) => void)
| ((arg: Record<string, unknown>) => void)
const main = <
Params extends Parameters<InnerFn>,
>(fn: (...params: Params) => void) =>
(...args: Params) => fn(...args)
/**
* Ok
*/
const result0 = main(() => { }) // ok
result0() // ok
const result1 = main((a: string) => { })// ok
result1('hello') // ok
const result2 = main((a: number) => { }) // ok
result2(42) // ok
const result3 = main((a: { age: number }) => { }) // ok
result3({ age: 42 })
/**
* Errors
*/
const result4 = main((a: Promise<number>) => { }) // expected error
const result5 = main((a: number[]) => { }) // expected error
Explanation
Please dont use {}
as a type because it is very general type. Everything is an object in javascript and typescript. Hence {}
can't be used as a constraint. It is better to use Record<string, unknown>
for such purpose.
Parameters
- returns a tuple of all arguments of passed function.
P.S. I hope you don't mind that I have used arrow function instead of function
. I'm not saying it is better, it just the matter of a style.
Upvotes: 1