Serginho
Serginho

Reputation: 7490

Typescript Compiler Cannot invoke an expression whose type lacks a call signature

I'm using Array (from JavaScript) and List (from facebook immutable library). I create the following function:

fooFunc(descriptors: List<Descriptor> | Array<Descriptor>) {
  let descriptor = descriptors.find(d => d.game == game);
}

The compiler says:

Cannot invoke an expression whose type lacks a call signature.

Both objects have a method find with the same signature.

Any ideas?

I'm using TypeScript version: 2.0.2

Upvotes: 0

Views: 1270

Answers (1)

Nitzan Tomer
Nitzan Tomer

Reputation: 164147

It looks like the signatures of the two are different:

Array.find:

find(
    predicate: (value: T, index: number, obj: Array<T>) => boolean, 
    thisArg?: any
): T | undefined;

List.find:

find(
    predicate: (value?: V, key?: K, iter?: /*this*/Iterable<K, V>) => boolean,
    context?: any,
    notSetValue?: V
): V;

Because they have different signatures, then the union of them won't let you use the find method. For example:

interface A {
    fn(a: number): void;
}

interface B {
    fn(a: string): void;
}

type both = A | B;
let a: both;
a.fn(3); // error: Cannot invoke an expressions whose type lacks a call signature

That's because a.fn is of type (a: number) => void | (a: string) => void which is not callable.
The same as with your example.

Since you are only interested in the values then both signatures can work for you, so you can just cast it to one of them:

let descriptor = (descriptors as Array<Descriptor>).find(d => d.game == game);

And that will work just fine.
Another option is to do this:

type MyArrayType<T> = (Immutable.List<T> | Array<T>) & {
    find(predicate: (value: T) => boolean): T;
}

function fooFunc(descriptors: MyArrayType<Descriptor>) {
    let descriptor = descriptors.find(d => d.game == game);
}

Upvotes: 1

Related Questions