Skip to content

Type of variables lost when returning a function that reuses them #42275

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
MrChocolatine opened this issue Jan 10, 2021 · 3 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@MrChocolatine
Copy link

MrChocolatine commented Jan 10, 2021

Bug Report

🔎 Search Terms

type
lost
unknown

🕗 Version & Regression Information

  • This is a crash
  • This changed between versions ______ and _______
  • This is the behaviour in every version I tried, and I reviewed the FAQ for entries about "lost, type".
  • I was unable to test this on prior versions because I started on v4.
    However I tried with every versions in the Playground and I get the same result.

⏯ Playground Link

Playground link with relevant code - v4.1.3

Playground link with relevant code - Nightly / v4.2.0-dev.20210108

💻 Code

function attachEvent(element: Element, params: Array<unknown>): undefined | (() => void) {
  let [ selector, eventType, fn ] = params

  if (
    typeof selector !== 'string'
    || typeof eventType !== 'string'
    || typeof fn !== 'function'
  ) {
    return
  }

  // `selector` is correctly seen as `string`
  let targetElem = element.querySelector(selector)

  if ( !targetElem ) {
    return
  }

  // Cast required as type `Function` is not enough for `addEventListener`
  let eventHandler = fn as () => unknown

  // `eventType` is correctly seen as `string`
  targetElem.addEventListener(eventType, eventHandler)

  // `targetElem` is back to `Object is possibly null`
  // `eventType` is now seen as `unknown` again
  return () => targetElem.removeEventListener(eventType, eventHandler)

  // Solution: non-null assertion operation + cast `as string`, but why?
  // return () => targetElem!.removeEventListener(eventType as string, eventHandler)
}

🙁 Actual behaviour

  • Type of variable targetElem is lost and fallback to its initial type.
  • Type of variable eventType is lost and fallback to its initial type.

🙂 Expected behaviour

Since the context does not change and their type has been narrowed down, the types of the variables targetElem and eventType should be kept.

Possible related issues

Thank you for your feedback.

@MrChocolatine MrChocolatine changed the title Type of variable lost when returning a function that reuses this variable Type of variables lost when returning a function that reuses them Jan 10, 2021
@MartinJohns
Copy link
Contributor

Duplicate of #9998.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jan 12, 2021
@typescript-bot
Copy link
Collaborator

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

@MrChocolatine
Copy link
Author

MrChocolatine commented Feb 14, 2021

Despite this ticket having been closed, just a heads-up for whoever that might come across the same issue:

Declaring variables with const instead of let fixed my initial issue, see this playground with TypeScript v4.1.3.


To give a bit of a context, I was working on an Ember.js project and historically we had this lint rule that recommends to only use const at the top-level of any file:
https://github.com/DockYard/eslint-plugin-ember-suave/blob/5c1e256254768172aeba3e10843036d7b3503484/docs/rules/no-const-outside-module-scope.md

Since we migrated the codebase to TypeScript this rule was not relevant anymore and, as we can see, in this case it fixed the issue.

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