Search code examples
typescripttype-safety

How to use a proper type Function on a generic function?


I'm trying to fix the @typescript-eslint/ban-types lint errors:

warning Don't use Function as a type @typescript-eslint/ban-types

I agree that Function is an unsafe type and should be replaced with a proper function type, such as () => void.

But my code is a little complex, and I have no idea how to avoid it here since I'm using typeof that returns a Function.

Here's a simplified version of my code. The full version is here.

function start<T>(args: unknown[], couldBeAFunction: T) {
  if (typeof couldBeAFunction === 'function') {
    runFunction(args, couldBeAFunction); // couldBeAFunction now is a Function
  }
}

function runFunction<T extends Function>(args: unknown[], target: T) {
  target.apply(args, args);
}

I can't replace runFunction<T extends Function> with runFunction<T extends (...args: unknown[]) => unknown>, otherwise I'll receive the following error on the runFunction call:

Argument of type 'T & Function' is not assignable to parameter of type '(...args: unknown[]) => unknown'. Type 'Function' provides no match for the signature '(...args: unknown[]): unknown'.ts(2345)

How can I solve this lint error?


Solution

  • You can use typeguard:

    type Fn = (...args: unknown[]) => unknown
    
    const isFn = (fn: unknown): fn is Fn => typeof fn === 'function'
    
    function start<T>(args: unknown[], couldBeAFunction: T) {
      if (isFn(couldBeAFunction)) {
        runFunction(args, couldBeAFunction); // couldBeAFunction now is a Function
      }
    }
    
    function runFunction<T extends Fn>(args: unknown[], target: T) {
      target.apply(args, args);
    }
    

    Playground