How to call a function from another function, but keep all of the types for that specific function
I have use case, where I want to register multiple functions, and then call them from another function.
Here's the code
const combineFunctions = <T extends Record<keyof T, T[keyof T]>>(funcs: T) => {
return (key: keyof T, params: Parameters<T[keyof T]>): ReturnType<T[keyof T]> => funcs[key](params)
}
interface AddNumbersArgumentsType {
a: number
b: number
}
type AddNumbersReturnType = number
const addNumbers = (params: AddNumbersArgumentsType): AddNumbersReturnType => {
return params.a + params.b
}
interface CombineStringWithNumberArgumentsType {
c: string
d: number
}
type CombineStringWithNumberReturnType = string
const combineStringWithNumber = (params: CombineStringWithNumberArgumentsType): CombineStringWithNumberReturnType => {
return params.c + params.d
}
const funcs = {
addNumbers,
combineStringWithNumber
}
const funkies = combineFunctions<typeof funcs>(funcs)
const a = funkies('addNumbers', [{ // Here Paramters util function forces me to send an array
// Here it should autocomplete only correct params from AddNumbersArgumentsType
// But it gives me an option of all arguments all functions take
}]) // => Return type is not gotten correctly, but is a combinations of all functions return types
Main problems being
-
Parameters
util forces me to use an array while I just want to get the type of params - Arguments autocomplete for all params from all functions instead of taking argument types specific to the function
- Same problem with return type as with arguments
You can see the code running here
Thanks in advance :)
Solution 1:
You need an extra type parameter on the inner function to capture the actual key passed in, and use that instead of keyof T
to index into T
. That will bake ts resolve the actual function being passed in.
Parameters
returns a tuple of parameters (there could be more) but you can use tuple and rest parameters to fix this.
const combineFunctions = <T extends Record<PropertyKey, (...a: any[]) => any>>(funcs: T) => {
return <K extends keyof T>(key: K, ...params: Parameters<T[K]>): ReturnType<T[K]> => funcs[key](...params)
}
///.....
const funcs = {
addNumbers,
combineStringWithNumber
}
const funkies = combineFunctions<typeof funcs>(funcs)
const a = funkies('addNumbers', {a: 1, b: 1}) // all type cheked
Playground Link