Skip to content

Discriminated union not narrowed if the declared variable isn't constant and the discriminator has an additional catch-all type #62929

@dword-design

Description

@dword-design

🔎 Search Terms

discriminator
discriminated
discriminating
catch-all
default

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about search for discriminator/discriminating

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBeKBvKATAlgZwMYBOWAtlgHYCGwcBAXFAOQBmCDANFAG4UA2ArhHrNWUAL5QAPmky5CJclRr0cwImQDmHbv0GMARhQIMxAbgBQZvHDIqoLOPXiIU6bPiKlK1Oo3vsuvAJCBkZiUBQ4sAjmZlhMUAAU9gB0bnKeigTISCjCcAwAlGhmUFBWNnA8EMk8cOpJCMnaAgUmUAD07VAAKuC6ecZSDCEMZqJAA

💻 Code

✅ Works (discriminator with default type, constant object):

type Foo = { discriminator: 'foo', value: 'foo' } | { discriminator: string, value: 'bar' };

const foo: Foo = { discriminator: 'foo', value: 'bar' };

if (foo.discriminator === 'foo') {
  console.log(foo.value); // Type: 'foo'
}

✅ Works (discriminator with excluding value, cast object):

type Foo = { discriminator: 'foo', value: 'foo' } | { discriminator: 'bar', value: 'bar' };

const foo: Foo = { discriminator: 'foo', value: 'bar' } as Foo;

if (foo.discriminator === 'foo') {
  console.log(foo.value); // Type: 'foo'
}

❌ Doesn't work (discriminator with default type, cast object):

type Foo = { discriminator: 'foo', value: 'foo' } | { discriminator: string, value: 'bar' };

const foo: Foo = { discriminator: 'foo', value: 'bar' } as Foo;

if (foo.discriminator === 'foo') {
  console.log(foo.value); // Type: 'foo' | 'bar'
}

It looks a bit like TypeScript is missing information to narrow down the discriminator if the object type wasn't set as the constant object. But from a coder's perspective, it's Foo in all cases.

I found other issues that look related but have different examples:

🙁 Actual behavior

The type isn't narrowed down.

🙂 Expected behavior

The type is narrowed down to the matching discriminator.

Additional information about the issue

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions