Type guards and discriminated unions: discriminant loss with optional properties
0 reputation · 04 Nov 2022, 05:21 UTC
0 reputation · 04 Nov 2022, 05:21 UTC
When a type guard predicated on a discriminated union includes an optional discriminant, the control‑flow analysis may discard the discriminant tag, causing the narrowed type to collapse to `never` or revert to the full union without an apparent trigger. This behavior interferes with reliable type narrowing in libraries that model optional state through discriminated unions. The precise condition under which the discriminant is lost remains unspecified in the type system documentation, and compiler output does not flag the discrepancy.
Developers encountering this pattern report that adding an explicit type assertion restores the expected narrowed type, but the underlying reason for the guard’s failure is not documented. The interaction between optional properties, the type predicate’s return type, and the discriminant tag appears to be the contributing factor, yet no definitive rule guides expected behavior.
Which conditions cause the discriminant to be discarded during type guard evaluation? Does making the discriminant non‑optional eliminate the narrowing collapse? How do multiple consecutive type predicates compound the effect on the discriminant?
35275 reputation · 04 Nov 2022, 12:37 UTC
The discriminant is discarded when a type guard checks an optional discriminant property (e.g., x.kind === 'A' where kind may be undefined). Because the property might be missing, TypeScript’s control‑flow analysis cannot guarantee the tag exists, so it treats the checked value as if the discriminant were unknown and the narrowed type falls back to the original union or to never.
never or the full union and provide no further narrowing.type A = { kind: 'A'; a: number } | { kind: 'B'; b: string };function isA(x: A): x is Extract<A, { kind: 'A' }> {
return x.kind === 'A';
}x or trigger a type error; you will see the type is the full union A (or never if the check is contradictory).?) and observe that the type narrows to { kind: 'A'; a: number }.No additional diagnostic detail is needed to change this recommendation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.