diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fd786799b8b..4305227dab7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14340,6 +14340,11 @@ namespace ts { return false; } + function hasNarrowableDeclaredType(expr: Node) { + const type = getDeclaredTypeOfReference(expr); + return !!(type && type.flags & TypeFlags.Union); + } + function findDiscriminantProperties(sourceProperties: Symbol[], target: Type): Symbol[] | undefined { let result: Symbol[] | undefined; for (const sourceProperty of sourceProperties) { @@ -15373,9 +15378,9 @@ namespace ts { // We have '==', '!=', '====', or !==' operator with 'typeof xxx' and string literal operands const target = getReferenceCandidate(typeOfExpr.expression); if (!isMatchingReference(reference, target)) { - // For a reference of the form 'x.y', a 'typeof x === ...' type guard resets the - // narrowed type of 'y' to its declared type. - if (containsMatchingReference(reference, target)) { + // For a reference of the form 'x.y', where 'x' has a narrowable declared type, a + // 'typeof x === ...' type guard resets the narrowed type of 'y' to its declared type. + if (containsMatchingReference(reference, target) && hasNarrowableDeclaredType(target)) { return declaredType; } return type; @@ -15516,9 +15521,9 @@ namespace ts { function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { const left = getReferenceCandidate(expr.left); if (!isMatchingReference(reference, left)) { - // For a reference of the form 'x.y', an 'x instanceof T' type guard resets the - // narrowed type of 'y' to its declared type. - if (containsMatchingReference(reference, left)) { + // For a reference of the form 'x.y', where 'x' has a narrowable declared type, an + // 'x instanceof T' type guard resets the narrowed type of 'y' to its declared type. + if (containsMatchingReference(reference, left) && hasNarrowableDeclaredType(left)) { return declaredType; } return type;