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

Union types are not being narrowed down correctly in 4.3 #44401

Closed
KnorpelSenf opened this issue Jun 2, 2021 · 6 comments · Fixed by #44771
Closed

Union types are not being narrowed down correctly in 4.3 #44401

KnorpelSenf opened this issue Jun 2, 2021 · 6 comments · Fixed by #44771
Labels
Bug A bug in TypeScript
Milestone

Comments

@KnorpelSenf
Copy link

Bug Report

Potentially related to #44382.

🔎 Search Terms

  • union types
  • narrowing
  • 4.3

🕗 Version & Regression Information

  • This changed between versions 4.2 and 4.3

⏯ Playground Link

Playground link with relevant code

💻 Code

interface X {
  a?: { aProp: string };
  b?: { bProp: string };
}
type AorB = { a: object; b: undefined } | { a: undefined; b: object };

declare const q: X & AorB;

if (q.a !== undefined) {
  q.a.aProp;
} else {
  // q.b is incorrectly inferred as potentially undefined:
  q.b.bProp;
}

🙁 Actual behavior

q.b is inferred as potentially undefined in the else block. Given that q conforms with AorB, and q.a is known to be undefined in the else block, this is incorrect.

🙂 Expected behavior

q.b should be inferred as present. In particular, it should be { bProp: string }.

@KnorpelSenf KnorpelSenf changed the title Union types are not being narrowed down correctly Union types are not being narrowed down correctly in 4.3 Jun 2, 2021
@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Jun 2, 2021
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jun 2, 2021
@KnorpelSenf
Copy link
Author

@RyanCavanaugh is it planned to fix this at some point in the near future? I see you added it to the backlog, but that list contains 2.6K issues and some of them are years old.

If it turns out that this bug will be ignored, then I'd prefer to start looking for workarounds now, and beginning to rewrite a number of TypeScript projects that rely on the old behaviour.

@RyanCavanaugh
Copy link
Member

@KnorpelSenf barring other people encountering this or other prioritization data appearing, I don't expect it'd be fixed soon unless someone from outside the team wrote a PR (not unlikely but obviously I cannot predict when that might happen)

@KnorpelSenf
Copy link
Author

Thanks for the quick response, then I'll start looking into workarounds

@caojoshua
Copy link
Contributor

Potential fix in #44771

Regression in this commit

Potentially related to #44382.

I've found that the regression is not related to this issue.

@KnorpelSenf
Copy link
Author

As a workaround it is possible to add a superfluous check for undefined. (Alternatively, a type cast could be performed.) This is obviously not a satisfying solution.

Naturally, I would much rather have see #44771 merged.

RyanCavanaugh pushed a commit that referenced this issue Jul 13, 2021
…#44771)

* Fix "Union types are not being narrowed down correctly in 4.3 #44401"

* On undefined constraint, add the original type to constraints.
@denis-sokolov
Copy link

I’ve got another way to reproduce this. Has been fixed by the same fix in #44771, I’m leaving this in case it helps anyone with a similar case find this issue.

Union of an intersection type is not narrowed down after type guards: Playground

type T = { x: string } & { y: string };

const good: T | "none" = "none";
// good is narrowed to "none" in the conditional
if (good === "none") good.toUpperCase();

const bad = "none" as T | "none";
// bad is not narrowed in the conditional, “toUpperCase does not exist on type T”
if (bad === "none") bad.toUpperCase();

// typeof good === typeof bad === (T | "none")

const noIntersection = "none" as { x: string; y: string } | "none";
// noIntersection is narrowed to "none" in the conditional
if (noIntersection === "none") noIntersection.toUpperCase();

Worked correctly in 4.2. Works incorrectly on 4.3. Works incorrectly on 4.4.0-dev.20210712. Works correctly on 4.4.0-dev.20210714.

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

Successfully merging a pull request may close this issue.

4 participants