Skip to content

Incorrect type narrowing for tuples #61332

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
Florian-Mt opened this issue Mar 2, 2025 · 2 comments
Closed

Incorrect type narrowing for tuples #61332

Florian-Mt opened this issue Mar 2, 2025 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@Florian-Mt
Copy link

🔎 Search Terms

"narrow tuple", "tuple inference"

🕗 Version & Regression Information

This is the behavior in every version I tried in the playground (v3.3, v4.5, v5.8, nightly), and I reviewed the FAQ about "tuple", "narrow", "inference".

⏯ Playground Link

https://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgCrIN4F8BQOED2IAzmMmADbCkBcyA2ugD7IgCuFFANGsi+5wC6yALwMB3VhwqCcAejnIA8gGlkwGOSql1xZAApmUzgEp6wgEZsyIAmRgEo5NgAcKEYjytkAksgC2EHAgyHDObigWEAhwbMQo7iAA5mAAFrrIMMAAHhAAJngwbCAIYMBEyKnBee76lNRgdIw8qIImmDjIXVoNOLg4Ggb1pAB0EABu0ACedaIAfOTIAIQiYhIm7Rid3VUgNRB12mAmfXiDhw30AAzCK2vSyABkjz2k9ACMt6vGFJvbXbt9hdSCdcEA

💻 Code

interface T {}

const tlist: [T | null, T | null] = [null, null]
// OK if tlist is (T | null)[] but not for tuples, but I mean a tuple because length is fixed

function handle(tlist: [T, T]) {
    tlist
}

if (tlist.every(t => t !== null)) {
    handle(tlist)
}

if (tlist[0] !== null && tlist[1] !== null) {
    handle(tlist)
}

🙁 Actual behavior

handle(tlist) throws in the TS compiler:

Argument of type '[T | null, T | null] & T[]' is not assignable to parameter of type '[T, T]'.
  Types of property '0' are incompatible.
    Type 'T | null' is not assignable to type 'T'.
      Type 'null' is not assignable to type 'T'.

🙂 Expected behavior

The condition in both if blocks should narrow tlist to the type [T, T], i.e. no error.

Additional information about the issue

It is OK if tlist is (T | null)[], but not for tuples. However, I really want to use a tuple here because the length of tlist is known and will never change.

@jcalz
Copy link
Contributor

jcalz commented Mar 3, 2025

Your second example is effectively a duplicate of #42384.


Your first example is a limitation of the type predicates on array methods like every(). You could merge your own call signature to handle tuples also, maybe like

interface Array<T> {
    every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any
    ): this is { [I in keyof this]: this[I] & S };
}

Playground link

but I'm sure there are weird edge cases. Curiously I searched but I didn't find any existing issues filed about the type predicate methods on tuples, so maybe this isn't a duplicate of an existing issue? There are near-misses about map() on tuples not producing tuples.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Mar 3, 2025
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Mar 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants