@@ -7895,10 +7895,11 @@ namespace ts {
7895
7895
case SyntaxKind.ExclamationEqualsToken:
7896
7896
case SyntaxKind.EqualsEqualsEqualsToken:
7897
7897
case SyntaxKind.ExclamationEqualsEqualsToken:
7898
- if (isNullOrUndefinedLiteral(expr.right)) {
7898
+ if (isNullOrUndefinedLiteral(expr.left) || isNullOrUndefinedLiteral(expr. right)) {
7899
7899
return narrowTypeByNullCheck(type, expr, assumeTrue);
7900
7900
}
7901
- if (expr.left.kind === SyntaxKind.TypeOfExpression && expr.right.kind === SyntaxKind.StringLiteral) {
7901
+ if (expr.left.kind === SyntaxKind.TypeOfExpression && expr.right.kind === SyntaxKind.StringLiteral ||
7902
+ expr.left.kind === SyntaxKind.StringLiteral && expr.right.kind === SyntaxKind.TypeOfExpression) {
7902
7903
return narrowTypeByTypeof(type, expr, assumeTrue);
7903
7904
}
7904
7905
break;
@@ -7911,18 +7912,20 @@ namespace ts {
7911
7912
}
7912
7913
7913
7914
function narrowTypeByNullCheck(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
7914
- // We have '==', '!=', '===', or '!==' operator with 'null' or 'undefined' on the right
7915
+ // We have '==', '!=', '===', or '!==' operator with 'null' or 'undefined' on one side
7915
7916
const operator = expr.operatorToken.kind;
7917
+ const nullLike = isNullOrUndefinedLiteral(expr.left) ? expr.left : expr.right;
7918
+ const narrowed = isNullOrUndefinedLiteral(expr.left) ? expr.right : expr.left;
7916
7919
if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) {
7917
7920
assumeTrue = !assumeTrue;
7918
7921
}
7919
- if (!strictNullChecks || !isMatchingReference(reference, getReferenceFromExpression(expr.left ))) {
7922
+ if (!strictNullChecks || !isMatchingReference(reference, getReferenceFromExpression(narrowed ))) {
7920
7923
return type;
7921
7924
}
7922
7925
const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
7923
7926
const facts = doubleEquals ?
7924
7927
assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull :
7925
- expr.right .kind === SyntaxKind.NullKeyword ?
7928
+ nullLike .kind === SyntaxKind.NullKeyword ?
7926
7929
assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull :
7927
7930
assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined;
7928
7931
return getTypeWithFacts(type, facts);
@@ -7931,12 +7934,12 @@ namespace ts {
7931
7934
function narrowTypeByTypeof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
7932
7935
// We have '==', '!=', '====', or !==' operator with 'typeof xxx' on the left
7933
7936
// and string literal on the right
7934
- const left = getReferenceFromExpression((<TypeOfExpression>expr.left).expression);
7935
- const right = <LiteralExpression>expr.right;
7936
- if (!isMatchingReference(reference, left )) {
7937
+ const narrowed = getReferenceFromExpression((<TypeOfExpression>( expr.left.kind === SyntaxKind.TypeOfExpression ? expr.left : expr.right) ).expression);
7938
+ const literal = <LiteralExpression>( expr.right.kind === SyntaxKind.StringLiteral ? expr.right : expr.left) ;
7939
+ if (!isMatchingReference(reference, narrowed )) {
7937
7940
// For a reference of the form 'x.y', a 'typeof x === ...' type guard resets the
7938
7941
// narrowed type of 'y' to its declared type.
7939
- if (containsMatchingReference(reference, left )) {
7942
+ if (containsMatchingReference(reference, narrowed )) {
7940
7943
return declaredType;
7941
7944
}
7942
7945
return type;
@@ -7949,14 +7952,14 @@ namespace ts {
7949
7952
// We narrow a non-union type to an exact primitive type if the non-union type
7950
7953
// is a supertype of that primtive type. For example, type 'any' can be narrowed
7951
7954
// to one of the primitive types.
7952
- const targetType = getProperty(typeofTypesByName, right .text);
7955
+ const targetType = getProperty(typeofTypesByName, literal .text);
7953
7956
if (targetType && isTypeSubtypeOf(targetType, type)) {
7954
7957
return targetType;
7955
7958
}
7956
7959
}
7957
7960
const facts = assumeTrue ?
7958
- getProperty(typeofEQFacts, right .text) || TypeFacts.TypeofEQHostObject :
7959
- getProperty(typeofNEFacts, right .text) || TypeFacts.TypeofNEHostObject;
7961
+ getProperty(typeofEQFacts, literal .text) || TypeFacts.TypeofEQHostObject :
7962
+ getProperty(typeofNEFacts, literal .text) || TypeFacts.TypeofNEHostObject;
7960
7963
return getTypeWithFacts(type, facts);
7961
7964
}
7962
7965
0 commit comments