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

TypeScript does not correctly infer type of Array.pop on nonempty arrays #47292

Closed
tristan00b opened this issue Jan 3, 2022 · 3 comments
Closed

Comments

@tristan00b
Copy link

Bug Report

TypeScript does not correctly infer the return type of Array.pop when called on a nonempty array.

I have seen issue #30406, and the comment stating that this issue "cannot be tracked", but I'm unsure what that means and whether it applies where an array is guaranteed to be nonempty such as in the cases below.

If anything there is an in consistency between using pop and indexing with arr.length - 1. Ideally I would like to see pop be inferred correctly, but consistent behaviour between pop and indexing would be the next best thing.

🔎 Search Terms

🕗 Version & Regression Information

I am using

  • tsc: 4.5.2 with "target": "ESNext" and "module": "ESNext"
  • VS Code: 1.63.2
  • JavaScript and TypeScript Nightly VS Code plugin: 4.6.2022010
  • Tested with nightly version in Playground

⏯ Playground Link

Playground Link

💻 Code

🙁 Actual behavior

function f0(): string
{
  return ''.split('.').pop() // infers string|undefined
}

function f1(): string
{
    return [''].pop() // infers string|undefined
}

function f2(): number
{
  return [1].pop() // infers number|undefined
}

function f3(): string
{
//   const components = ''.split('.')
//   return components[components.length -1] // infers string

    return ''.split('.')[0] // infers string
}

🙂 Expected behavior

function f0(): string
{
  return ''.split('.').pop() // infers string
}

function f1(): string
{
    return [''].pop() // infers string
}

function f2(): number
{
  return [1].pop() // infers number
}

Or

function f3(): string|undefined
{
//   const components = ''.split('.')
//   return components[components.length -1] // infers string|undefined

    return ''.split('.')[0] // infers string|undefined
}
@MartinJohns
Copy link
Contributor

The type system has no information that the arrays are really not empty, and the type checker works based on the type system. Only tuples are guaranteed to not be empty, but they're not mutable, so no pop method.

@fatcerberus
Copy link

As for consistent behavior between pop and indexing: that’s why noUncheckedIndexedAccess was introduced.

And yeah, “not tracked” means what it sounds like, TS just sees “called .pop() on something of type number[]” which isn’t enough information to guarantee a non-nullish result; that you called it on an array literal is irrelevant because TS doesn’t have a “non-empty array” type.

@tristan00b
Copy link
Author

@MartinJohns, @fatcerberus That makes sense. I also must have missed/forgotten about noUncheckedIndexedAccess. Will close now.

Thank you for the clarifications!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants