skip to Main Content

I have a method that can receive multiple types of functions. I have a specific function constant in my application, and I want to prohibit any functions from being passed whose signature matches it – without modifying the method parameter type.

I attempt to do this using instanceof

const constant = (number) => number

class Context {
    execute(fn: (...args?: any) => any) {
        if (fn instanceof constant)
            return false
    }
}

but find that the instanceof operation is apparently not supported between functions.

What techniques are available to check during runtime if a function has the same signature as another function, in TypeScript?

Note that "in TypeScript" does not mean I require a solution that is only possible in TypeScript. Vanilla JavaScript approaches are acceptable too, if there is no way for TS to make it nicer.

2

Answers


  1. Well you must understand that when you talk about runtime you already omit Typescript. So as an example you can check the pattern of the function as string. But its quite Dirty way. I would question what are you trying to achieve because if you use TS then it may be not the best idea to run dynamic functions. But anyways, here is how your resulted js should look like.

    const constant = (number) => number
    
    class Context {
        execute(fn) {        
             if (typeof fn === 'function' && /(number) => /.test(fn.toString())) {
               console.log('Function has same pattern as constant');
             }
        }
    }
    
    
    const inst = new Context();
    inst.execute(constant);

    Here is TS version

    const constant = (number: number) => number
    
    class Context {
        execute(fn: (args?: any) => any): void {
            if (typeof fn === 'function' && /(number) => /.test(fn.toString())) {
               console.log('Function has same pattern as constant');
             }
        }
    }
    
    const inst = new Context();
    inst.execute(constant); // true
    inst.execute((notNumber: number) => notNumber); // not true
    
    Login or Signup to reply.
  2. You can’t do that check at runtime because typings are only available at compile time. However you can add a constraint with a conditional type so that any functions of type const constant: (number: number) => number are rejected using the type never.

    const constant = (number: number) => number;
    
    type ForbiddenSignature = typeof constant;
    //   ^? type ForbiddenSignature = (number: number) => number
    
    class Context {
      execute<T>(fn: T extends ForbiddenSignature ? never : T) {
        // implementaiton
      }
    }
    
    const context = new Context();
    context.execute(constant);
    //              ~~~~~~~~ Argument of type '(number: number) => number'
    //                       is not assignable to parameter of type 'never'.
    context.execute((x: string) => {}); // works
    context.execute((x: number) => {}); // works
    context.execute(() => {}); //works
    context.execute((x: number) => 0); // error
    //              ~~~~~~~~~~~~~~~~ Argument of type '(x: number) => number'
    //                               is not assignable to parameter of type 'never'.
    

    TypeScript Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search