Skip to content

Can't call forEach on number[] | ReadonlyArray<never> #16716

New issue

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

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

Already on GitHub? # to your account

Closed
ghost opened this issue Jun 23, 2017 · 2 comments
Closed

Can't call forEach on number[] | ReadonlyArray<never> #16716

ghost opened this issue Jun 23, 2017 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@ghost
Copy link

ghost commented Jun 23, 2017

TypeScript Version: nightly (2.5.0-dev.20170623)

Code

const empty: ReadonlyArray<never> = [];
function f(nums: number[] | undefined) {
    const a = nums || empty;
    a.forEach(n => {});
}

Expected behavior:

No error.

Actual behavior:

4     a.forEach(n => {});
      ~~~~~~~~~~~~~~~~~~

src/a.ts(4,5): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '((callbackfn: (value: never, index: number, array: ReadonlyArray<never>) => void, thisArg?: any) ...' has no compatible call signatures.


4     a.forEach(n => {});
                ~

src/a.ts(4,15): error TS7006: Parameter 'n' implicitly has an 'any' type.
@ghost ghost mentioned this issue Jun 23, 2017
@jcalz
Copy link
Contributor

jcalz commented Jun 23, 2017

I think the first error message is from the same issue reported in #16644:

var a = [1, 2, 3];
(a as number[]).filter(x => typeof x === 'string'); // fine
(a as (number | string)[]).filter(x => typeof x === 'string'); // fine
(a as number[] | (number | string)[]).filter(x => typeof x === 'string'); // error!

var b = [];
(b as number[]).forEach(x => console.log(x)); // fine
(b as never[]).forEach(x => console.log(x)); // fine
(b as number[] | never[]).forEach(x => console.log(x)); // error!

In that issue, @kujon was asking that A[] | B[] should reduce to (A|B)[] which is consistent with the way TypeScript currently treats arrays as covariant in their content type. But possibly-mutable arrays should be invariant in their type, so maybe that fix would be going farther in the wrong direction.

The other way of looking at this issue is:

type Overloaded<A, B> = {
  (a: A): void;
  (b: B): void;
}
function exploded<A, B>(f: Overloaded<A,B>, ab: A | B): void {
  f(ab); // error!
  var isA: (ab) => ab is A;
  isA(ab) ? f(ab) : f(ab); // workaround, no error 
}

TypeScript can't take an overloaded or generic function and realize that if it can resolve a parameter of type A and separately resolve a parameter of type B, then it "should" be able to handle a parameter of type A|B. But here be dragons.

@ghost
Copy link
Author

ghost commented Jun 23, 2017

Thanks, I'll mark this as a duplicate of that issue.

@ghost ghost closed this as completed Jun 23, 2017
@ghost ghost added the Duplicate An existing issue was already created label Jun 23, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
This issue was closed.
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

1 participant