Typescript function union type lacks a call signature

Viewed 568
interface F1 {
  (a, b): any;
}

interface F2 {
  (a): any;
}

type F3 = F1 | F2;

const f: F3 = (a) => {
  console.log(123, a);
}

f(1) // Error

I'm stumbled upon one of the mysterious problems in TypeScript (3.1.4). While I call f(), the compiler says Cannot invoke an expression whose type lacks a call signature. Type 'F3' has no compatible call signatures. [2349].

This is even strange since all of the above code works fine until that f(1).

Am I missing something here? If any, how can I give the union typed function typing?

I know I can do something like this

interface T {
  (a, b): any;
  (a): any;
}

But then I have to define function in such a way

function (a, b?) {

}

which I don't like that much. Any help/feedback would be appreciated.

1 Answers

In typescript the | operator describes a union type:

A union type describes a value that can be one of several types. We use the vertical bar (|) to separate each type, so number | string | boolean is the type of a value that can be a number, a string, or a boolean.

interface F1 {
  (a, b): any;
}

interface F2 {
  (a): any;
}

type F3 = F1 | F2;
const f: F3 = (a) => {
  console.log(123, a);
}

const isF2 = (a): a is F2 => true; // Typeguard
if (isF2(f)) { 
  f(1); // OK
}

What you are looking for is the & operator, or the intersection type:

Intersection types represent values that simultaneously have multiple types. A value of an intersection type A & B is a value that is both of type A and type B.

interface F1 {
  (a, b): any;
}

interface F2 {
  (a): any;
}

type F4 = F1 & F2;
const g: F4 = (a) => {
  console.log(123, a);
}

g(1); // OK

You can play around with these examples in this Typescript playground

Related