Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typing (string[] | string[][]) not recognized properly #6453

Closed
rogierschouten opened this issue Jan 12, 2016 · 6 comments
Closed

Typing (string[] | string[][]) not recognized properly #6453

rogierschouten opened this issue Jan 12, 2016 · 6 comments
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead

Comments

@rogierschouten
Copy link

Hi all,

I have two small examples that I expected to be equivalent but tsc accepts only one:

Working example:

let myArray: (string | string[])[];
myArray.forEach((element: string | string[]): void => {
}); // no compile error

Not-working example:

let myArray: string[] | string[][];
myArray.forEach((element: string | string[]): void => {
}); // compile error: Cannot invoke an expression whose type lacks a call signature
@ahejlsberg
Copy link
Member

Methods are available on a union type only when each of the underlying methods have identical parameter lists (which isn't the case here). This is by design. From a typing perspective it technically isn't correct to do what you expected in all cases (i.e. union together the parameter types of each of the underlying methods). For example, say you had a method with two parameters of the array element type. The underlying signatures would be foo(x: string, y: string) and foo(x: string[], y: string[]), and we'd produce a combined signature foo(x: string | string[], y: string | string[]). That would permit you to call with x and y arguments of different types, which is incorrect.

@ahejlsberg ahejlsberg added the By Design Deprecated - use "Working as Intended" or "Design Limitation" instead label Jan 12, 2016
@mhegazy mhegazy closed this as completed Jan 12, 2016
@BairDev
Copy link

BairDev commented Jul 14, 2016

@ahejlsberg Maybe I'm at a loss, but why is foo(x: string, y: string)

a method with two parameters of the array element type

Of course, here you can't do x.forEach() in the function body.

I mean (and maybe OP, either), that here a is an array anyway.

let a: number[] | string[];
// later
a.forEach(); // compile error: Cannot invoke an expression whose type lacks a call signature

What is the technical difference between string[] | number[] and (string | number)[]?

@sledorze
Copy link

sledorze commented Jul 14, 2016

@BairDev

string[] | number[] means either an array of string OR an array of number.

(string | number)[] means an array of string OR number, in a non exclusive way.
so that: ["a", 5] is such an array that cannot be bound to string[] nor to number[].

@sledorze
Copy link

sledorze commented Jul 14, 2016

@ahejlsberg is there any notion of (co/contra)variance in typescript? I think something can come out from properly considering that aspect.

In your example, we may also consider the signature as a whole:
(x : string, y: string) => R | (x : string[], y : string[]) => R

@sledorze
Copy link

@mhegazy I think it could be reopened

@kitsonk
Copy link
Contributor

kitsonk commented Jul 14, 2016

Contra/covariance is covered in #1394 as well as somewhat related to variadic kinds proposed in #5453.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead
Projects
None yet
Development

No branches or pull requests

6 participants