Skip to content

Using nullish coalescing with untyped field in constructor trigger TS7022 #55013

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

Open
6XGate opened this issue Jul 13, 2023 · 1 comment
Open
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone

Comments

@6XGate
Copy link

6XGate commented Jul 13, 2023

Bug Report

Using nullish coalescing in a constructor to initialize a class member with no type annotation will result in a TS7022 error.

🔎 Search Terms

nullish, coalescing, 7022, ??, and ts7022

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about nullish coalescing and type inference.

⏯ Playground Link

Playground link with relevant code

💻 Code

export class Node {
  #parent

  #children = new Children(this)

  constructor (parent?: Node | null | undefined) {
    // Remove `??` and the code after and the code compiled. Now #parent is undefined which is not desired.
    this.#parent = parent ?? null
  }

  get parent () { return this.#parent }

  get children () { return this.#children }
}

export class Children {
  #parent
  #head
  #tail

  constructor (parent: Node) {
    this.#parent = parent
    this.#head = new Node(parent)
    this.#tail = new Node(parent)
  }
}

🙁 Actual behavior

Attempting to compile the example code results in a TS7022 error: '#parent' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.

🙂 Expected behavior

The code should compile and #parent should be typed as Node | null.

@Andarist
Copy link
Contributor

It's a very similar problem to the one that I diagnosed here (the code paths that we hit here are almost identical at the end, only the origin of the problem is slightly different)

The problem is that this binary expression in the initializer creates a union type here (of the left type and the right type) and that union is a subject of subtype reduction. That in turn asks for properties of the parent's properties and that encounters a cycle.

This particular case here probably could be avoided since the right type is null and the left type is not nullish but the other mentioned issue shows us that there are other, similar, cases for which this wouldn't help at all. A smarter fix would be appreciated but I don't have ideas for it.

@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases labels Jul 18, 2023
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jul 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Projects
None yet
Development

No branches or pull requests

3 participants