@@ -39252,7 +39252,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3925239252 }
3925339253 return numberType;
3925439254 }
39255- return getUnaryResultType (operandType);
39255+ return getUnaryArithmeticResultType (operandType);
3925639256 case SyntaxKind.ExclamationToken:
3925739257 checkTruthinessOfType(operandType, node.operand);
3925839258 const facts = getTypeFacts(operandType, TypeFacts.Truthy | TypeFacts.Falsy);
@@ -39270,7 +39270,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3927039270 Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access,
3927139271 );
3927239272 }
39273- return getUnaryResultType (operandType);
39273+ return getUnaryArithmeticResultType (operandType);
3927439274 }
3927539275 return errorType;
3927639276 }
@@ -39293,11 +39293,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3929339293 Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access,
3929439294 );
3929539295 }
39296- return getUnaryResultType (operandType);
39296+ return getUnaryArithmeticResultType (operandType);
3929739297 }
3929839298
39299- function getUnaryResultType (operandType: Type): Type {
39300- if (maybeTypeOfKind (operandType, TypeFlags.BigIntLike)) {
39299+ function getUnaryArithmeticResultType (operandType: Type): Type {
39300+ if (maybeTypeOfKindConsideringBaseConstraint (operandType, TypeFlags.BigIntLike)) {
3930139301 return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike)
3930239302 ? numberOrBigIntType
3930339303 : bigintType;
@@ -40009,35 +40009,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4000940009 // otherwise just check each operand separately and report errors as normal
4001040010 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);
4001140011 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);
4004140014 if (leftOk && rightOk) {
4004240015 checkAssignmentOperator(resultType);
4004340016 switch (operator) {
@@ -40228,6 +40201,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4022840201 return Debug.fail();
4022940202 }
4023040203
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+ } else if (!maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.BigIntLike) && !maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.BigIntLike)) {
40211+ // If neither could be bigint, implicit coercion results in a number result
40212+ return numberType;
40213+ }
40214+ // At least one is assignable to bigint, so check that both are
40215+ else if (bothAreBigIntLike(leftType, rightType)) {
40216+ switch (operator) {
40217+ case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
40218+ case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
40219+ reportOperatorError();
40220+ break;
40221+ case SyntaxKind.AsteriskAsteriskToken:
40222+ case SyntaxKind.AsteriskAsteriskEqualsToken:
40223+ if (languageVersion < ScriptTarget.ES2016) {
40224+ error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later);
40225+ }
40226+ }
40227+ return bigintType;
40228+ }
40229+
40230+ // Exactly one of leftType/rightType is assignable to bigint
40231+ reportOperatorError(bothAreBigIntLike);
40232+ return errorType;
40233+ }
40234+
4023140235 function bothAreBigIntLike(left: Type, right: Type): boolean {
4023240236 return isTypeAssignableToKind(left, TypeFlags.BigIntLike) && isTypeAssignableToKind(right, TypeFlags.BigIntLike);
4023340237 }
0 commit comments