Skip to content

Union between Uint8Array and Array<number> does not work for reduce function #44593

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

Closed
fizker opened this issue Jun 15, 2021 · 3 comments
Closed
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@fizker
Copy link

fizker commented Jun 15, 2021

Bug Report

The compiler cannot find an intersection between the reduce function for number[] and Uint8Array.

From the error message, it looks like the compiler is raising an issue because of the fourth parameter having different types, but since I don't use the fourth parameter, it hardly seems relevant in this specific case.

🔎 Search Terms

  • Uint8Array

🕗 Version & Regression Information

I see this issue in v3.3.3333, v4.3.2 (current stable) and v4.4.0-dev.20210615 (current nightly).

⏯ Playground Link

Playground link with relevant code

💻 Code

// This function fails
function combined(x: Uint8Array | Array<number>): number {
  return x.reduce((s: number, x: number) => s + x * x, 0)
}

// This function has no issues
function uiint8array(x: Uint8Array): number {
  return x.reduce((s: number, x: number) => s + x * x, 0)
}

// This function has no issues
function numberarray(x: Array<number>): number {
  return x.reduce((s: number, x: number) => s + x * x, 0)
}

🙁 Actual behavior

The code works fine at runtime, but the typescript compiler raises the following error for the Uint8Array | Array<number> case:

This expression is not callable.
  Each member of the union type '{ (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number): number; <U>(callbackfn: (previousValue: U, currentValue: numb...' has signatures, but none of those signatures are compatible with each other.(2349)
(property) reduce: {
    (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number): number;
    (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number): number;
    <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U): U;
} | {
    ...;
}

🙂 Expected behavior

No errors are produced.

@MartinJohns
Copy link
Contributor

Related, or potential duplicate: #44063

@RyanCavanaugh
Copy link
Member

It's allowed to call methods of union types if we can determine that we can safely check it correctly (this used to be always disallowed).

In this case, we can't check it correctly. The problem here is that reduce passes the array itself as the fourth argument to the callback, so a hypothetical receiving function would have to be validated to accept both a UIntArray8 and number[] in that position, which we could either check with union (which would fail), by iterating the possible constituents (combinatorially explosive), or by doing some kind of lookahead on the target arity to figure out that we could just not care (sound, but sort of rare outside of the specific example of reduce).

See also #9239 for potential next steps of improving this logic.

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jun 15, 2021
@icholy
Copy link

icholy commented Mar 4, 2023

I just ran into this with the following snippet:

function isStringArray(a: string[] | number[]): a is string[] {
	return a.every((v) => typeof v === 'string');
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants