Serginho Serginho - 1 month ago 13
TypeScript Question

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

Answer

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);
}
Comments