Home > Blockchain >  conditionally call a function with its params
conditionally call a function with its params

Time:05-12

Having several functions, I would like do not call them if there is no need (logic in needToCalculate), used by a generic function calculateIfNeeded

// helper functions
function sum(a: number, b: number) { return a   b; }  // complex real logic (CRL)
function bum(a: number, code: string) { return (code=="B") ? a*a : a a; } // CRL
function zum(code: string) { return (code=="Z") ? 5 : 8; }                // CRL

function needToCalculate(code: string) {return false} // CRL

Question: what type should have the param func of the method calculateIfNeeded bellow?

// calculator function
function calculateIfNeeded(code: string, func: ???, ...args: any[]){
    return needToCalculate(code) ? func(args): NaN
}

// main function
let a = 4, b = 9

let res = calculateIfNeeded("A", sum, a, b);  console.log(res);    
res = calculateIfNeeded("B", bum, a, "B");    console.log(res);    
res = calculateIfNeeded("C", zum, "Z");       console.log(res);

Playground

CodePudding user response:

since it looks like you can return anything from the calculation (assuming you're not limited by any restrictions), the type of func will be

func: (...args: any[]) => any

That means you expected to receive in func any number of arguments with any type, and expect to return from func any type.

EDIT (inspired by @Dima Parzhitsky comment):

You can so something like this:

function calculateIfNeeded<F extends any[]>(code: string, func: (...args: F)=>number, ...args: F) : number{
    return needToCalculate(code) ? func(...args): NaN
}

Define F to be some extension of any arguments (any[]).

Then the func receives F and return any, and the args themselves are F as well.

Then you just call func(...args)

CodePudding user response:

Extending upon my comment, you

/**
 * This represents not just _any function_, but one that can be
 * given as the second parameter (`func`) of `calculateIfNeeded`.
 * The call signature must be added explicitly, because apparently
 * TypeScript cannot know, that a union of callables is also callable
 */
type Func = (typeof sum | typeof bum | typeof zum) & ((...args: never[]) => number);

function calculateIfNeeded<F extends Func>(code: string, func: F, ...args: Parameters<F>): number {
    return needToCalculate(code) ? func(...args): NaN;
}

Try it.

Note, that I had to change func(args) to func(...args), because args is an array, but neither of sum, bum, or zum accepts an array as an argument.

  • Related