Improve comparison operators type checking to disallow unions containing numbers as an operand (#52048)

This commit is contained in:
Mateusz Burzyński 2023-01-20 22:34:48 +01:00 коммит произвёл GitHub
Родитель e5515164eb
Коммит 2acbceed4b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 255 добавлений и 4 удалений

Просмотреть файл

@ -36336,9 +36336,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (checkForDisallowedESSymbolOperand(operator)) {
leftType = getBaseTypeOfLiteralType(checkNonNullType(leftType, left));
rightType = getBaseTypeOfLiteralType(checkNonNullType(rightType, right));
reportOperatorErrorUnless((left, right) =>
isTypeComparableTo(left, right) || isTypeComparableTo(right, left) || (
isTypeAssignableTo(left, numberOrBigIntType) && isTypeAssignableTo(right, numberOrBigIntType)));
reportOperatorErrorUnless((left, right) => {
if (isTypeAny(left) || isTypeAny(right)) {
return true;
}
const leftAssignableToNumber = isTypeAssignableTo(left, numberOrBigIntType);
const rightAssignableToNumber = isTypeAssignableTo(right, numberOrBigIntType);
return leftAssignableToNumber && rightAssignableToNumber ||
!leftAssignableToNumber && !rightAssignableToNumber && areTypesComparable(left, right);
});
}
return booleanType;
case SyntaxKind.EqualsEqualsToken:

Просмотреть файл

@ -6,9 +6,41 @@ tests/cases/conformance/expressions/binaryOperators/comparisonOperator/compariso
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(17,14): error TS2367: This comparison appears to be unintentional because the types 'T' and 'U' have no overlap.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(18,14): error TS2367: This comparison appears to be unintentional because the types 'T' and 'U' have no overlap.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(19,14): error TS2367: This comparison appears to be unintentional because the types 'T' and 'U' have no overlap.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(23,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(26,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(31,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(34,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(40,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(43,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(48,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(51,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(57,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(60,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(65,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(68,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(74,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(77,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(82,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(85,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(91,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(94,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(99,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(102,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(108,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(111,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(116,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(119,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(125,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(128,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(133,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(136,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(142,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(145,16): error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(150,16): error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts(153,16): error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
==== tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts (8 errors) ====
==== tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNoRelationshipTypeParameter.ts (40 errors) ====
enum E { a, b, c }
var a: boolean;
@ -48,136 +80,200 @@ tests/cases/conformance/expressions/binaryOperators/comparisonOperator/compariso
// operator <
var r1a1 = t < a;
var r1a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r1a3 = t < c;
var r1a4 = t < d;
var r1a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r1a6 = t < f;
var r1a7 = t < g;
var r1b1 = a < t;
var r1b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r1b3 = c < t;
var r1b4 = d < t;
var r1b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r1b6 = f < t;
var r1b7 = g < t;
// operator >
var r2a1 = t < a;
var r2a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r2a3 = t < c;
var r2a4 = t < d;
var r2a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r2a6 = t < f;
var r2a7 = t < g;
var r2b1 = a < t;
var r2b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r2b3 = c < t;
var r2b4 = d < t;
var r2b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r2b6 = f < t;
var r2b7 = g < t;
// operator <=
var r3a1 = t < a;
var r3a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r3a3 = t < c;
var r3a4 = t < d;
var r3a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r3a6 = t < f;
var r3a7 = t < g;
var r3b1 = a < t;
var r3b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r3b3 = c < t;
var r3b4 = d < t;
var r3b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r3b6 = f < t;
var r3b7 = g < t;
// operator >=
var r4a1 = t < a;
var r4a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r4a3 = t < c;
var r4a4 = t < d;
var r4a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r4a6 = t < f;
var r4a7 = t < g;
var r4b1 = a < t;
var r4b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r4b3 = c < t;
var r4b4 = d < t;
var r4b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r4b6 = f < t;
var r4b7 = g < t;
// operator ==
var r5a1 = t < a;
var r5a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r5a3 = t < c;
var r5a4 = t < d;
var r5a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r5a6 = t < f;
var r5a7 = t < g;
var r5b1 = a < t;
var r5b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r5b3 = c < t;
var r5b4 = d < t;
var r5b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r5b6 = f < t;
var r5b7 = g < t;
// operator !=
var r6a1 = t < a;
var r6a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r6a3 = t < c;
var r6a4 = t < d;
var r6a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r6a6 = t < f;
var r6a7 = t < g;
var r6b1 = a < t;
var r6b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r6b3 = c < t;
var r6b4 = d < t;
var r6b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r6b6 = f < t;
var r6b7 = g < t;
// operator ===
var r7a1 = t < a;
var r7a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r7a3 = t < c;
var r7a4 = t < d;
var r7a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r7a6 = t < f;
var r7a7 = t < g;
var r7b1 = a < t;
var r7b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r7b3 = c < t;
var r7b4 = d < t;
var r7b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r7b6 = f < t;
var r7b7 = g < t;
// operator !==
var r8a1 = t < a;
var r8a2 = t < b;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'number'.
var r8a3 = t < c;
var r8a4 = t < d;
var r8a5 = t < e;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'E'.
var r8a6 = t < f;
var r8a7 = t < g;
var r8b1 = a < t;
var r8b2 = b < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'T'.
var r8b3 = c < t;
var r8b4 = d < t;
var r8b5 = e < t;
~~~~~
!!! error TS2365: Operator '<' cannot be applied to types 'E' and 'T'.
var r8b6 = f < t;
var r8b7 = g < t;
}

Просмотреть файл

@ -0,0 +1,11 @@
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNumberOperand.ts(3,1): error TS2365: Operator '>=' cannot be applied to types 'number | Promise<number>' and 'number'.
==== tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNumberOperand.ts (1 errors) ====
// repro #52036
declare const t1: number | Promise<number>
t1 >= 0 // error
~~~~~~~
!!! error TS2365: Operator '>=' cannot be applied to types 'number | Promise<number>' and 'number'.
!!! related TS2773 tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNumberOperand.ts:3:1: Did you forget to use 'await'?

Просмотреть файл

@ -0,0 +1,9 @@
=== tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNumberOperand.ts ===
// repro #52036
declare const t1: number | Promise<number>
>t1 : Symbol(t1, Decl(comparisonOperatorWithNumberOperand.ts, 1, 13))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
t1 >= 0 // error
>t1 : Symbol(t1, Decl(comparisonOperatorWithNumberOperand.ts, 1, 13))

Просмотреть файл

@ -0,0 +1,10 @@
=== tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithNumberOperand.ts ===
// repro #52036
declare const t1: number | Promise<number>
>t1 : number | Promise<number>
t1 >= 0 // error
>t1 >= 0 : boolean
>t1 : number | Promise<number>
>0 : 0

Просмотреть файл

@ -0,0 +1,113 @@
tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts(81,12): error TS2365: Operator '>' cannot be applied to types 'string | number' and 'number'.
==== tests/cases/conformance/controlFlow/controlFlowWhileStatement.ts (1 errors) ====
let cond: boolean;
function a() {
let x: string | number;
x = "";
while (cond) {
x; // string
}
}
function b() {
let x: string | number;
x = "";
while (cond) {
x; // string
x = 42;
break;
}
}
function c() {
let x: string | number;
x = "";
while (cond) {
x; // string
x = undefined;
if (typeof x === "string") continue;
break;
}
}
function d() {
let x: string | number;
x = "";
while (x = x.length) {
x; // number
x = "";
}
}
function e() {
let x: string | number;
x = "";
while (cond) {
x; // string | number
x = 42;
x; // number
}
x; // string | number
}
function f() {
let x: string | number | boolean | RegExp | Function;
x = "";
while (cond) {
if (cond) {
x = 42;
break;
}
if (cond) {
x = true;
continue;
}
x = /a/;
}
x; // string | number | boolean | RegExp
}
function g() {
let x: string | number | boolean | RegExp | Function;
x = "";
while (true) {
if (cond) {
x = 42;
break;
}
if (cond) {
x = true;
continue;
}
x = /a/;
}
x; // number
}
function h1() {
let x: string | number | boolean;
x = "";
while (x > 1) {
~~~~~
!!! error TS2365: Operator '>' cannot be applied to types 'string | number' and 'number'.
x; // string | number
x = 1;
x; // number
}
x; // string | number
}
declare function len(s: string | number): number;
function h2() {
let x: string | number | boolean;
x = "";
while (cond) {
x = len(x);
x; // number
}
x; // string | number
}
function h3() {
let x: string | number | boolean;
x = "";
while (cond) {
x; // string | number
x = len(x);
}
x; // string | number
}

Просмотреть файл

@ -0,0 +1,6 @@
// @strict: true
// @noEmit: true
// repro #52036
declare const t1: number | Promise<number>
t1 >= 0 // error