@@ -39252,7 +39252,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
39252
39252
}
39253
39253
return numberType;
39254
39254
}
39255
- return getUnaryResultType (operandType);
39255
+ return getUnaryArithmeticResultType (operandType);
39256
39256
case SyntaxKind.ExclamationToken:
39257
39257
checkTruthinessOfType(operandType, node.operand);
39258
39258
const facts = getTypeFacts(operandType, TypeFacts.Truthy | TypeFacts.Falsy);
@@ -39270,7 +39270,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
39270
39270
Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access,
39271
39271
);
39272
39272
}
39273
- return getUnaryResultType (operandType);
39273
+ return getUnaryArithmeticResultType (operandType);
39274
39274
}
39275
39275
return errorType;
39276
39276
}
@@ -39293,11 +39293,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
39293
39293
Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access,
39294
39294
);
39295
39295
}
39296
- return getUnaryResultType (operandType);
39296
+ return getUnaryArithmeticResultType (operandType);
39297
39297
}
39298
39298
39299
- function getUnaryResultType (operandType: Type): Type {
39300
- if (maybeTypeOfKind (operandType, TypeFlags.BigIntLike)) {
39299
+ function getUnaryArithmeticResultType (operandType: Type): Type {
39300
+ if (maybeTypeOfKindConsideringBaseConstraint (operandType, TypeFlags.BigIntLike)) {
39301
39301
return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike)
39302
39302
? numberOrBigIntType
39303
39303
: bigintType;
@@ -40009,35 +40009,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
40009
40009
// otherwise just check each operand separately and report errors as normal
40010
40010
const leftOk = checkArithmeticOperandType(left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true);
40011
40011
const rightOk = checkArithmeticOperandType(right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true);
40012
- let resultType: Type;
40013
- // If both are any or unknown, allow operation; assume it will resolve to number
40014
- if (
40015
- (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) ||
40016
- // Or, if neither could be bigint, implicit coercion results in a number result
40017
- !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || maybeTypeOfKind(rightType, TypeFlags.BigIntLike))
40018
- ) {
40019
- resultType = numberType;
40020
- }
40021
- // At least one is assignable to bigint, so check that both are
40022
- else if (bothAreBigIntLike(leftType, rightType)) {
40023
- switch (operator) {
40024
- case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
40025
- case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
40026
- reportOperatorError();
40027
- break;
40028
- case SyntaxKind.AsteriskAsteriskToken:
40029
- case SyntaxKind.AsteriskAsteriskEqualsToken:
40030
- if (languageVersion < ScriptTarget.ES2016) {
40031
- error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later);
40032
- }
40033
- }
40034
- resultType = bigintType;
40035
- }
40036
- // Exactly one of leftType/rightType is assignable to bigint
40037
- else {
40038
- reportOperatorError(bothAreBigIntLike);
40039
- resultType = errorType;
40040
- }
40012
+
40013
+ const resultType = getBinaryArithmeticResultType(leftType, rightType);
40041
40014
if (leftOk && rightOk) {
40042
40015
checkAssignmentOperator(resultType);
40043
40016
switch (operator) {
@@ -40228,6 +40201,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
40228
40201
return Debug.fail();
40229
40202
}
40230
40203
40204
+ function getBinaryArithmeticResultType(leftType: Type, rightType: Type): Type {
40205
+ if (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) {
40206
+ // If both are any or unknown, allow operation; assume it will resolve to number
40207
+ // (This is unsound, but it is not practical for untyped programs to
40208
+ // have `bigint|number` inferred everywhere; #41741)
40209
+ return numberType;
40210
+ }
40211
+ else if (!maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.BigIntLike) && !maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.BigIntLike)) {
40212
+ // If neither could be bigint, implicit coercion results in a number result
40213
+ return numberType;
40214
+ }
40215
+ // At least one is assignable to bigint, so check that both are
40216
+ else if (bothAreBigIntLike(leftType, rightType)) {
40217
+ switch (operator) {
40218
+ case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
40219
+ case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
40220
+ reportOperatorError();
40221
+ break;
40222
+ case SyntaxKind.AsteriskAsteriskToken:
40223
+ case SyntaxKind.AsteriskAsteriskEqualsToken:
40224
+ if (languageVersion < ScriptTarget.ES2016) {
40225
+ error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later);
40226
+ }
40227
+ }
40228
+ return bigintType;
40229
+ }
40230
+
40231
+ // Exactly one of leftType/rightType is assignable to bigint
40232
+ reportOperatorError(bothAreBigIntLike);
40233
+ return errorType;
40234
+ }
40235
+
40231
40236
function bothAreBigIntLike(left: Type, right: Type): boolean {
40232
40237
return isTypeAssignableToKind(left, TypeFlags.BigIntLike) && isTypeAssignableToKind(right, TypeFlags.BigIntLike);
40233
40238
}
0 commit comments