Question

TypeScript discriminated union narrows in if but not in switch — exhaustiveness check fails

83dbd1af-8b65-4e94-a468-ee378f5f2b79

I have a discriminated union in TypeScript but the exhaustiveness check doesn't work in a switch statement:

type Event =
  | { type: 'click'; x: number; y: number }
  | { type: 'keypress'; key: string }
  | { type: 'scroll'; delta: number }

function handle(event: Event) {
  switch (event.type) {
    case 'click': return handleClick(event) // narrows correctly
    case 'keypress': return handleKey(event) // narrows correctly
    // missing 'scroll' case
    default: {
      const _exhaustive: never = event // ERROR: Type '{ type: "scroll"; ... }' is not assignable to 'never'
      // But sometimes this doesn't error — why?
    }
  }
}

The never check works sometimes but not always. Specifically it fails when the union is imported from a generated type file. Is this a TS compiler bug or is there a subtlety with how discriminated unions are resolved across module boundaries?