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

Inverted union type narrowing was broken in 4.9 #58861

Open
Woodz opened this issue Jun 14, 2024 · 2 comments
Open

Inverted union type narrowing was broken in 4.9 #58861

Woodz opened this issue Jun 14, 2024 · 2 comments
Labels
Bug A bug in TypeScript Help Wanted You can do this
Milestone

Comments

@Woodz
Copy link

Woodz commented Jun 14, 2024

πŸ”Ž Search Terms

"union type", "narrowing", "inverted", "4.9"

πŸ•— Version & Regression Information

⏯ Playground Link

Playground link

πŸ’» Code

interface Foo { foo: string; }

interface Bar { bar: string; }

interface Baz { baz: string; }

function myFunction(input: Foo | Bar | Baz) {
    const isBaz = 'baz' in input;
    const isBar = 
      //'bar' in input; // This works to narrow `bar` when true and narrow `foo` in the else block
      !('foo' in input) && !isBaz; // This works to narrow `bar` when true but does not narrow `foo` in the else block
    let x: string;
    if (isBaz) {
      x = input.baz;
    } else if (isBar) {
      x = input.bar;
    } else {
      // In 4.8.4 and earlier, `input` is narrowed to `Foo`
      // In 4.9.5 and later, `input` is narrowed to `Foo | ((Foo | Bar) & Record<"baz", unknown>)`
      x = input.foo;
    }
}

πŸ™ Actual behavior

In 4.9.5 and later, in the else block, input.foo incorrectly narrows and errors

πŸ™‚ Expected behavior

In 4.8.4 and earlier, in the else block, input.foo correctly narrows

Additional information about the issue

No response

@Andarist
Copy link
Contributor

bisects to #50666

@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript Help Wanted You can do this labels Jun 14, 2024
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jun 14, 2024
@Andarist
Copy link
Contributor

Andarist commented Jun 14, 2024

This playground might also be helpful to see what is happening. The inverted narrowing works just fine:

function myFunction4(input: Foo | Bar | Baz) {
  if (!("baz" in input)) {
    input;
    // ^? (parameter) input: Foo | Bar
  } else {
    input;
    // ^? (parameter) input: Baz
  }
}

The issue here is specific to the fact that inverted narrowing is used on the type is already refined using the same non-inverted check.

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

No branches or pull requests

3 participants