2

Say that you have something which can either be an array of numbers or strings and you want to map over this array. Using TypeScript the following ways of expressing such a situation are all accepted by the type checker.

[1, 2].map(e => console.log(e));
let arr: string[] | number[] = [1, 2];
arr.map(e => console.log(e));

But if we add an explicit static type cast, to the same type, to describe arr the compiler will throw an error our way:

(arr as string[] | number[]).map(e => console.log(e)); 
// Cannot invoke an expression whose type lacks a call signature. 
// Type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (...' has no compatible call signatures.

Do you know why this would happen, or is it possible that this is an issue with the compiler itself?

1
  • 2
    To get that to work I believe you'd have to use the intersection type: (arr as string[] & number[]).map(e => console.log(e)); . Either that, or use a type guard. Commented Mar 19, 2018 at 14:29

1 Answer 1

2

You are actually seeing flow control analysis in action in the first case. Since you only assign a number array to your variable the compiler will decide that the actual type for arr is number[] and it will run with that, making the map call valid. If you actually assign a string[] to the variable, with the compiler not being able to statically decide which code path will actually be taken you will receive the same error as you do with an explicit cast:

declare var decider : boolean
let arr: string[] | number[] = decider ? [1, 2] : ['a', 'b'];
arr.map(e => console.log(e)); // Will be an error 

As to why map is not callable on the union of string[] | number[] the reason is that the type of map will be a union type of the two available signatures from string[] and number[] the signatures are not identical and no merging will occur between them. Since a union of two signatures is not callable, you will get the error.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.