Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map over union array type?

I have the following structure:

interface Test1 {
    number: number;
}
interface Test2 extends Test1 {
    text: string;
}

let test: Test1[] | Test2[] = [];
test.map(obj => {}); // does not work

I am getting the error:

Cannot invoke an expression whose type lacks a call signature. Type '{ (this: [Test1, Test1, Test1, Test1, Test1], callbackfn: (this: void, value: Test1, index: nu...' has no compatible call signatures

How can I map over the test variable?

like image 993
Murat Karagöz Avatar asked Mar 27 '18 10:03

Murat Karagöz


People also ask

When should I use Typecript union type?

TypeScript - Union TypeScript allows us to use more than one data type for a variable or a function parameter. This is called union type. Consider the following example of union type. In the above example, variable code is of union type, denoted using (string | number) .

What is .MAP in JavaScript?

map() creates a new array from calling a function for every array element. map() calls a function once for each element in an array. map() does not execute the function for empty elements.


Video Answer


1 Answers

Edit for 4.2

map has become callable now, but you still need an explicit type annotation on its argument to get it to work as expected (the type parameter is no contextually typed)

let test: Test1[] | Test2[] = [];
test.map((obj: Test1 | Test2) => {});

Playground Link

This situation is likely to improve in future versions making this answer mostly obsolete (see PR that will correctly synthesize contextual types for parameters)

Original answer pre 4.2

The problem is that for union types, members which are functions will also be typed as union types, so the type of map will be (<U>(callbackfn: (value: Test1, index: number, array: Test1[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: Test2, index: number, array: Test2[]) => U) Which as far as typescript is concerned is not callable.

You can either declare an array of the union of Test1 and Test2

let test: (Test1 | Test2)[] = [];
test.map(obj => {}); 

Or you can use a type assertion when you make the call:

let test: Test1[] | Test2[] = [];
(test as Array<Test1|Test2>).map(o=> {});
like image 122
Titian Cernicova-Dragomir Avatar answered Oct 19 '22 00:10

Titian Cernicova-Dragomir