Repository navigation
Incorrect post-narrowing merge of typeof symbol | {} | (() => void)Β #45467
Description
Activity
IllusionMH commented
on Aug 16, 2021 ContributorMore actionsMore like it gave up on keeping union and used
{}as common type ("widened"?).Because everything from that union is assignable to
{}const symbol = Symbol("Test"); // no errors const x1: 1 | "a" | typeof symbol | {} | (() => void) = 123; const x2: 1 | "a" | typeof symbol | {} | (() => void) = "not a"; const x3: 1 | "a" | typeof symbol | {} | (() => void) = Symbol("not Test"); const x4: 1 | "a" | typeof symbol | {} | (() => void) = (a: number) => a; // no errors const y1: {} = 1; const y2: {} = "a"; const y3: {} = Symbol("a"); const y4: {} = () => {}; // errors as expected const z1: 1 | "a" | typeof symbol | (() => void) = 123; const z2: 1 | "a" | typeof symbol | (() => void) = "not a"; const z3: 1 | "a" | typeof symbol | (() => void) = Symbol("not Test"); const z4: 1 | "a" | typeof symbol | (() => void) = (a: number) => a;
Not sure about your use case but
objectinstead of{}might be closer to what you are looking for.RyanCavanaugh commented
on Aug 16, 2021 MemberMore actionsSimpler repro
const symbol = Symbol("Test"); function f(x: typeof symbol | {} | (() => void)): void { if (typeof x === "function") { } x; }
These issues happen when the re-unioning logic gets messed up when merging the two incoming control flow edges. But there's not much reason to write this code in first place.
- changed the title
[-]Switch incorrectly narrows type[/-][+]Incorrect post-narrowing merge of `typeof symbol | {} | (() => void)`[/+]on Aug 16, 2021 This looks like subtype reduction, similar to what happens in #39434.
Andarist commented
on Aug 13, 2023 ContributorMore actionsRyan Cavanaugh (@RyanCavanaugh) Jake Bailey (@jakebailey) should this still be classified as a bug? the weird behavior with multiple switch cases from the OP was already "fixed" by #49119 . As Ryan's answer suggests - this is just union reduction at play when merging control flow paths. I don't exactly see this particular example to be a good motivation for reconsidering the used algorithm.
RyanCavanaugh commented
on Aug 16, 2023 MemberMore actionsI think ideally we would still go back to the declared type -- you could imagine an algorithm that detects that all incoming paths have an uninterrupted flow from the origin and does this -- but yeah, this isn't wrong per our normal stance of "subtype reduction can occur at any time".
- locked as resolved and limited conversation to collaborators
on Oct 21, 2025
Bug Report
π Search Terms
switch incorrectly narrows type
π Version & Regression Information
v4.3.5
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
Starting from 4th switch the type of x is narrowed to {}.
π Expected behavior
The type of x should not be narrowed