Skip to content

Commit bc7f86c

Browse files
committed
Improved undefined/null handling for arithmetic operators
1 parent 2711303 commit bc7f86c

File tree

1 file changed

+18
-29
lines changed

1 file changed

+18
-29
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12332,16 +12332,18 @@ namespace ts {
1233212332
}
1233312333

1233412334
function checkNonNullExpression(node: Expression | QualifiedName) {
12335-
const type = checkExpression(node);
12336-
if (strictNullChecks) {
12337-
const kind = getFalsyFlags(type) & TypeFlags.Nullable;
12338-
if (kind) {
12339-
error(node, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ?
12340-
Diagnostics.Object_is_possibly_null_or_undefined :
12341-
Diagnostics.Object_is_possibly_undefined :
12342-
Diagnostics.Object_is_possibly_null);
12343-
}
12344-
return getNonNullableType(type);
12335+
return checkNonNullType(checkExpression(node), node);
12336+
}
12337+
12338+
function checkNonNullType(type: Type, errorNode: Node): Type {
12339+
const kind = (strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable;
12340+
if (kind) {
12341+
error(errorNode, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ?
12342+
Diagnostics.Object_is_possibly_null_or_undefined :
12343+
Diagnostics.Object_is_possibly_undefined :
12344+
Diagnostics.Object_is_possibly_null);
12345+
const t = getNonNullableType(type);
12346+
return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? unknownType : t;
1234512347
}
1234612348
return type;
1234712349
}
@@ -14880,17 +14882,9 @@ namespace ts {
1488014882
if (leftType === silentNeverType || rightType === silentNeverType) {
1488114883
return silentNeverType;
1488214884
}
14883-
// TypeScript 1.0 spec (April 2014): 4.19.1
14884-
// These operators require their operands to be of type Any, the Number primitive type,
14885-
// or an enum type. Operands of an enum type are treated
14886-
// as having the primitive type Number. If one operand is the null or undefined value,
14887-
// it is treated as having the type of the other operand.
14888-
// The result is always of the Number primitive type.
14889-
if (leftType.flags & TypeFlags.Nullable) leftType = rightType;
14890-
if (rightType.flags & TypeFlags.Nullable) rightType = leftType;
1489114885

14892-
leftType = getNonNullableType(leftType);
14893-
rightType = getNonNullableType(rightType);
14886+
leftType = checkNonNullType(leftType, left);
14887+
rightType = checkNonNullType(rightType, right);
1489414888

1489514889
let suggestedOperator: SyntaxKind;
1489614890
// if a user tries to apply a bitwise operator to 2 boolean operands
@@ -14915,16 +14909,11 @@ namespace ts {
1491514909
if (leftType === silentNeverType || rightType === silentNeverType) {
1491614910
return silentNeverType;
1491714911
}
14918-
// TypeScript 1.0 spec (April 2014): 4.19.2
14919-
// The binary + operator requires both operands to be of the Number primitive type or an enum type,
14920-
// or at least one of the operands to be of type Any or the String primitive type.
14921-
14922-
// If one operand is the null or undefined value, it is treated as having the type of the other operand.
14923-
if (leftType.flags & TypeFlags.Nullable) leftType = rightType;
14924-
if (rightType.flags & TypeFlags.Nullable) rightType = leftType;
1492514912

14926-
leftType = getNonNullableType(leftType);
14927-
rightType = getNonNullableType(rightType);
14913+
if (!isTypeOfKind(leftType, TypeFlags.Any | TypeFlags.StringLike) && !isTypeOfKind(rightType, TypeFlags.Any | TypeFlags.StringLike)) {
14914+
leftType = checkNonNullType(leftType, left);
14915+
rightType = checkNonNullType(rightType, right);
14916+
}
1492814917

1492914918
let resultType: Type;
1493014919
if (isTypeOfKind(leftType, TypeFlags.NumberLike) && isTypeOfKind(rightType, TypeFlags.NumberLike)) {

0 commit comments

Comments
 (0)