mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 02:15:12 -06:00
Remove the rule that replaces a union of literal types with the base type when comparing equality to a type that isn't a union of literal types. (#27588)
type when comparing equality to a type that isn't a union of literal types. The rule is redundant because a primitive type is already directed- comparable to a value of that primitive type, and it causes errors to be missed when comparing a type parameter _constrained_ by a union of literal types to another union of literal types. The baseline changes look like improvements to me. Fixes #26758.
This commit is contained in:
parent
bd178746de
commit
6487d1ffe0
@ -23320,12 +23320,6 @@ namespace ts {
|
||||
case SyntaxKind.ExclamationEqualsToken:
|
||||
case SyntaxKind.EqualsEqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken:
|
||||
const leftIsLiteral = isLiteralType(leftType);
|
||||
const rightIsLiteral = isLiteralType(rightType);
|
||||
if (!leftIsLiteral || !rightIsLiteral) {
|
||||
leftType = leftIsLiteral ? getBaseTypeOfLiteralType(leftType) : leftType;
|
||||
rightType = rightIsLiteral ? getBaseTypeOfLiteralType(rightType) : rightType;
|
||||
}
|
||||
if (!isTypeEqualityComparableTo(leftType, rightType) && !isTypeEqualityComparableTo(rightType, leftType)) {
|
||||
reportOperatorError();
|
||||
}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
tests/cases/compiler/compareTypeParameterConstrainedByLiteralToLiteral.ts(5,5): error TS2367: This condition will always return 'false' since the types 'T' and '"x"' have no overlap.
|
||||
|
||||
|
||||
==== tests/cases/compiler/compareTypeParameterConstrainedByLiteralToLiteral.ts (1 errors) ====
|
||||
// Test for #26758
|
||||
|
||||
function foo<T extends "a" | "b">(t: T) {
|
||||
t === "a"; // Should be allowed
|
||||
t === "x"; // Should be error
|
||||
~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'T' and '"x"' have no overlap.
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
//// [compareTypeParameterConstrainedByLiteralToLiteral.ts]
|
||||
// Test for #26758
|
||||
|
||||
function foo<T extends "a" | "b">(t: T) {
|
||||
t === "a"; // Should be allowed
|
||||
t === "x"; // Should be error
|
||||
}
|
||||
|
||||
|
||||
//// [compareTypeParameterConstrainedByLiteralToLiteral.js]
|
||||
// Test for #26758
|
||||
function foo(t) {
|
||||
t === "a"; // Should be allowed
|
||||
t === "x"; // Should be error
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
=== tests/cases/compiler/compareTypeParameterConstrainedByLiteralToLiteral.ts ===
|
||||
// Test for #26758
|
||||
|
||||
function foo<T extends "a" | "b">(t: T) {
|
||||
>foo : Symbol(foo, Decl(compareTypeParameterConstrainedByLiteralToLiteral.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(compareTypeParameterConstrainedByLiteralToLiteral.ts, 2, 13))
|
||||
>t : Symbol(t, Decl(compareTypeParameterConstrainedByLiteralToLiteral.ts, 2, 34))
|
||||
>T : Symbol(T, Decl(compareTypeParameterConstrainedByLiteralToLiteral.ts, 2, 13))
|
||||
|
||||
t === "a"; // Should be allowed
|
||||
>t : Symbol(t, Decl(compareTypeParameterConstrainedByLiteralToLiteral.ts, 2, 34))
|
||||
|
||||
t === "x"; // Should be error
|
||||
>t : Symbol(t, Decl(compareTypeParameterConstrainedByLiteralToLiteral.ts, 2, 34))
|
||||
}
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
=== tests/cases/compiler/compareTypeParameterConstrainedByLiteralToLiteral.ts ===
|
||||
// Test for #26758
|
||||
|
||||
function foo<T extends "a" | "b">(t: T) {
|
||||
>foo : <T extends "a" | "b">(t: T) => void
|
||||
>t : T
|
||||
|
||||
t === "a"; // Should be allowed
|
||||
>t === "a" : boolean
|
||||
>t : T
|
||||
>"a" : "a"
|
||||
|
||||
t === "x"; // Should be error
|
||||
>t === "x" : boolean
|
||||
>t : T
|
||||
>"x" : "x"
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
tests/cases/compiler/expr.ts(87,5): error TS2367: This condition will always return 'false' since the types 'number' and 'string' have no overlap.
|
||||
tests/cases/compiler/expr.ts(88,5): error TS2367: This condition will always return 'false' since the types 'number' and 'boolean' have no overlap.
|
||||
tests/cases/compiler/expr.ts(88,5): error TS2367: This condition will always return 'false' since the types 'number' and 'false' have no overlap.
|
||||
tests/cases/compiler/expr.ts(94,5): error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
|
||||
tests/cases/compiler/expr.ts(95,5): error TS2367: This condition will always return 'false' since the types 'string' and 'boolean' have no overlap.
|
||||
tests/cases/compiler/expr.ts(95,5): error TS2367: This condition will always return 'false' since the types 'string' and 'false' have no overlap.
|
||||
tests/cases/compiler/expr.ts(98,5): error TS2367: This condition will always return 'false' since the types 'string' and 'E' have no overlap.
|
||||
tests/cases/compiler/expr.ts(115,5): error TS2367: This condition will always return 'false' since the types 'E' and 'string' have no overlap.
|
||||
tests/cases/compiler/expr.ts(116,5): error TS2367: This condition will always return 'false' since the types 'E' and 'false' have no overlap.
|
||||
@ -161,7 +161,7 @@ tests/cases/compiler/expr.ts(242,7): error TS2363: The right-hand side of an ari
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'number' and 'string' have no overlap.
|
||||
n==b;
|
||||
~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'number' and 'boolean' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'number' and 'false' have no overlap.
|
||||
n==i;
|
||||
n==n;
|
||||
n==e;
|
||||
@ -172,7 +172,7 @@ tests/cases/compiler/expr.ts(242,7): error TS2363: The right-hand side of an ari
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
|
||||
s==b;
|
||||
~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'string' and 'boolean' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'string' and 'false' have no overlap.
|
||||
s==i;
|
||||
s==s;
|
||||
s==e;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts(4,16): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
|
||||
tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts(5,16): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
|
||||
tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts(6,9): error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
|
||||
tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts(6,9): error TS2367: This condition will always return 'false' since the types 'string' and '1' have no overlap.
|
||||
tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts(8,16): error TS2339: Property 'unknownProperty' does not exist on type 'string'.
|
||||
tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts(12,10): error TS2403: Subsequent variable declarations must have the same type. Variable 'i' must be of type 'number', but here has type 'string'.
|
||||
tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts(16,10): error TS2403: Subsequent variable declarations must have the same type. Variable 'j' must be of type 'any', but here has type 'string'.
|
||||
@ -18,7 +18,7 @@ tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.
|
||||
!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
|
||||
if (x === 1) {
|
||||
~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'string' and '1' have no overlap.
|
||||
}
|
||||
let a3 = x.unknownProperty;
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
tests/cases/conformance/types/literal/stringLiteralsAssertionsInEqualityComparisons02.ts(3,9): error TS2367: This condition will always return 'false' since the types '"foo"' and '"baz"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsAssertionsInEqualityComparisons02.ts(5,9): error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsAssertionsInEqualityComparisons02.ts(5,9): error TS2367: This condition will always return 'false' since the types '"foo"' and 'number' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsAssertionsInEqualityComparisons02.ts(5,19): error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ tests/cases/conformance/types/literal/stringLiteralsAssertionsInEqualityComparis
|
||||
var b = "foo" !== ("bar" as "foo");
|
||||
var c = "foo" == (<number>"bar");
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'false' since the types '"foo"' and 'number' have no overlap.
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
||||
var d = "foo" === ("bar" as EnhancedString);
|
||||
@ -1,8 +1,12 @@
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(16,5): error TS2367: This condition will always return 'false' since the types '"foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(19,5): error TS2367: This condition will always return 'false' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(20,5): error TS2367: This condition will always return 'false' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(25,5): error TS2367: This condition will always return 'true' since the types '"foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(28,5): error TS2367: This condition will always return 'true' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(29,5): error TS2367: This condition will always return 'true' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts (2 errors) ====
|
||||
==== tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts (6 errors) ====
|
||||
interface Runnable {
|
||||
isRunning: boolean;
|
||||
}
|
||||
@ -24,7 +28,11 @@ tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(25,5
|
||||
b = "bar" === x;
|
||||
b = x === "bar";
|
||||
b = y === "bar";
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
b = "bar" === y;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
|
||||
b = x !== y;
|
||||
b = "foo" !== y
|
||||
@ -35,5 +43,9 @@ tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks03.ts(25,5
|
||||
b = "bar" !== x;
|
||||
b = x !== "bar";
|
||||
b = y !== "bar";
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'true' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
b = "bar" !== y;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'true' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(16,5): error TS2367: This condition will always return 'false' since the types '"foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(19,5): error TS2367: This condition will always return 'false' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(20,5): error TS2367: This condition will always return 'false' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(25,5): error TS2367: This condition will always return 'true' since the types '"foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(28,5): error TS2367: This condition will always return 'true' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(29,5): error TS2367: This condition will always return 'true' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts (2 errors) ====
|
||||
==== tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts (6 errors) ====
|
||||
interface Runnable {
|
||||
isRunning: boolean;
|
||||
}
|
||||
@ -24,7 +28,11 @@ tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(25,5
|
||||
b = "bar" == x;
|
||||
b = x == "bar";
|
||||
b = y == "bar";
|
||||
~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
b = "bar" == y;
|
||||
~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
|
||||
b = x != y;
|
||||
b = "foo" != y
|
||||
@ -35,5 +43,9 @@ tests/cases/conformance/types/literal/stringLiteralsWithEqualityChecks04.ts(25,5
|
||||
b = "bar" != x;
|
||||
b = x != "bar";
|
||||
b = y != "bar";
|
||||
~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'true' since the types 'Refrigerator | "foo"' and '"bar"' have no overlap.
|
||||
b = "bar" != y;
|
||||
~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'true' since the types '"bar"' and 'Refrigerator | "foo"' have no overlap.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(3,1): error TS2367: This condition will always return 'false' since the types 'symbol' and 'boolean' have no overlap.
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(5,1): error TS2367: This condition will always return 'true' since the types 'number' and 'symbol' have no overlap.
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(7,1): error TS2367: This condition will always return 'false' since the types 'symbol' and 'number' have no overlap.
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(9,1): error TS2367: This condition will always return 'true' since the types 'boolean' and 'symbol' have no overlap.
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(3,1): error TS2367: This condition will always return 'false' since the types 'symbol' and 'true' have no overlap.
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(5,1): error TS2367: This condition will always return 'true' since the types '0' and 'symbol' have no overlap.
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(7,1): error TS2367: This condition will always return 'false' since the types 'symbol' and '1' have no overlap.
|
||||
tests/cases/conformance/es6/Symbols/symbolType9.ts(9,1): error TS2367: This condition will always return 'true' since the types 'false' and 'symbol' have no overlap.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/Symbols/symbolType9.ts (4 errors) ====
|
||||
@ -9,16 +9,16 @@ tests/cases/conformance/es6/Symbols/symbolType9.ts(9,1): error TS2367: This cond
|
||||
s == s;
|
||||
s == true;
|
||||
~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'symbol' and 'boolean' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'symbol' and 'true' have no overlap.
|
||||
s != s;
|
||||
0 != s;
|
||||
~~~~~~
|
||||
!!! error TS2367: This condition will always return 'true' since the types 'number' and 'symbol' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'true' since the types '0' and 'symbol' have no overlap.
|
||||
s === s;
|
||||
s === 1;
|
||||
~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'symbol' and 'number' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'false' since the types 'symbol' and '1' have no overlap.
|
||||
s !== s;
|
||||
false !== s;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2367: This condition will always return 'true' since the types 'boolean' and 'symbol' have no overlap.
|
||||
!!! error TS2367: This condition will always return 'true' since the types 'false' and 'symbol' have no overlap.
|
||||
@ -0,0 +1,6 @@
|
||||
// Test for #26758
|
||||
|
||||
function foo<T extends "a" | "b">(t: T) {
|
||||
t === "a"; // Should be allowed
|
||||
t === "x"; // Should be error
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user