Home > Back-end >  My type can be a string or a function, but typescript says that the functions are not callable
My type can be a string or a function, but typescript says that the functions are not callable

Time:06-06

In my typescript file, I have a list of operations. Some of these are strings that needs to be executed and others are callable functions:

const operations: {title: string, method: Function | string}[] = [
      {
         title: `some powershell script`,
         method: `some powershell script`
      },
      {
         title: `function`,
         method: () => console.log("function"),
      }
];
if (typeof operations[i].method === `function`) {
     typeof operations[i].method() //  ERROR: This expression is not callable. No constituent of type 'string | Function' is callable.
}
if (typeof operations[i].method === `string`) {
     exec(operations[i].method) //  ERROR: Argument of type 'string | Function' is not assignable to parameter of type 'string'. Type 'Function' is not assignable to type 'string'.
}

Is there a way to resolve this typescript error without using any?

Thanks!

CodePudding user response:

How about forcing the type using as ?

The complete code would be:

const operations: {title: string, method: Function | string}[] = [
      {
         title: `some powershell script`,
         method: `some powershell script`
      },
      {
         title: `function`,
         method: () => console.log("function"),
      }
];
if (typeof operations[i].method === `function`) {
     const op = operations[i].method as Function;
     typeof op();
}
if (typeof operations[i].method === `string`) {
     const op = operations[i].method as string;
     exec(op);
}

CodePudding user response:

Your code does indeed work in newer versions of TypeScript, as you verify it here, so upgrading TypeScript would work.

However, the type Function is very generic, this is because you're using any implicitly for the return and ...args: any[] for the arguments, so if you want to avoid using any at all costs, type the object as such:

{title: string, method: (() => unknown) | string}

If you know the exact type that the method will return, you can use other types aside from unknown, if you don't, unknown will say it has a consistent type, which is the same as "any excluding never".

CodePudding user response:

Create an additional variable to check against, for example with object destructuring within a loop:

for (const operation of operations) {

  const { method } = operation;

  if (typeof method === `function`) {
       method(); // Function
  }

  if (method === `string`) {
       exec(method); // string
  }

  // Or even simpler
  // typeof method === `function` ? method() : exec(method);
}
  • Related