Skip to content

Commit 5754edc

Browse files
Final fix verification and code formatting
Co-authored-by: RyanCavanaugh <[email protected]>
1 parent c3df353 commit 5754edc

5 files changed

Lines changed: 621 additions & 20 deletions

File tree

src/compiler/checker.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22143,26 +22143,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2214322143
(source as NumberLiteralType).value === (target as NumberLiteralType).value
2214422144
) return true;
2214522145
if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true;
22146-
if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true;
22147-
if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true;
22148-
// For comparable relation, revert `this` type parameters back to their constrained class type
22149-
if (relation === comparableRelation) {
22150-
if (s & TypeFlags.TypeParameter && (source as TypeParameter).isThisType) {
22151-
const constraint = getConstraintOfTypeParameter(source as TypeParameter);
22152-
if (constraint && isTypeRelatedTo(constraint, target, relation)) {
22153-
return true;
22154-
}
22155-
}
22156-
if (t & TypeFlags.TypeParameter && (target as TypeParameter).isThisType) {
22157-
const constraint = getConstraintOfTypeParameter(target as TypeParameter);
22158-
if (constraint && isTypeRelatedTo(source, constraint, relation)) {
22159-
return true;
22160-
}
22161-
}
22162-
}
22163-
if (
22164-
s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName === target.symbol.escapedName &&
22165-
isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)
22146+
if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true;
22147+
if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true;
22148+
// For comparable relation, revert `this` type parameters back to their constrained class type
22149+
if (relation === comparableRelation) {
22150+
if (s & TypeFlags.TypeParameter && (source as TypeParameter).isThisType) {
22151+
const constraint = getConstraintOfTypeParameter(source as TypeParameter);
22152+
if (constraint && isTypeRelatedTo(constraint, target, relation)) {
22153+
return true;
22154+
}
22155+
}
22156+
if (t & TypeFlags.TypeParameter && (target as TypeParameter).isThisType) {
22157+
const constraint = getConstraintOfTypeParameter(target as TypeParameter);
22158+
if (constraint && isTypeRelatedTo(source, constraint, relation)) {
22159+
return true;
22160+
}
22161+
}
22162+
}
22163+
if (
22164+
s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName === target.symbol.escapedName &&
22165+
isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)
2216622166
) return true;
2216722167
if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) {
2216822168
if (s & TypeFlags.Union && t & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
thisTypeComparisonExtended.ts(26,13): error TS2367: This comparison appears to be unintentional because the types 'this' and 'CC' have no overlap.
2+
3+
4+
==== thisTypeComparisonExtended.ts (1 errors) ====
5+
// Test 1: Original issue - this === subclass instance should work
6+
class AA {
7+
do1() {
8+
const b = dd.getB();
9+
if (this === b) { // Should not error
10+
console.log("this === b");
11+
}
12+
}
13+
}
14+
15+
class BB extends AA {
16+
getB(): BB { return this; }
17+
}
18+
19+
let dd = new BB();
20+
dd.do1();
21+
22+
// Test 2: this === unrelated class should still error
23+
class CC {
24+
value: number = 42;
25+
}
26+
27+
class DD {
28+
test() {
29+
const c = new CC();
30+
if (this === c) { // Should still error - no relationship
31+
~~~~~~~~~~
32+
!!! error TS2367: This comparison appears to be unintentional because the types 'this' and 'CC' have no overlap.
33+
console.log("unrelated");
34+
}
35+
}
36+
}
37+
38+
// Test 3: Multiple inheritance levels
39+
class EE extends BB {
40+
getE(): EE { return this; }
41+
}
42+
43+
class FF extends EE {
44+
testMultiLevel() {
45+
const e = new EE();
46+
if (this === e) { // Should not error - FF extends EE
47+
console.log("multi-level inheritance");
48+
}
49+
}
50+
}
51+
52+
// Test 4: Interface implementation
53+
interface ITest {
54+
getValue(): number;
55+
}
56+
57+
class GG implements ITest {
58+
getValue() { return 42; }
59+
60+
testInterface() {
61+
const impl: ITest = new GG();
62+
if (this === impl) { // Should not error
63+
console.log("interface implementation");
64+
}
65+
}
66+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//// [tests/cases/compiler/thisTypeComparisonExtended.ts] ////
2+
3+
//// [thisTypeComparisonExtended.ts]
4+
// Test 1: Original issue - this === subclass instance should work
5+
class AA {
6+
do1() {
7+
const b = dd.getB();
8+
if (this === b) { // Should not error
9+
console.log("this === b");
10+
}
11+
}
12+
}
13+
14+
class BB extends AA {
15+
getB(): BB { return this; }
16+
}
17+
18+
let dd = new BB();
19+
dd.do1();
20+
21+
// Test 2: this === unrelated class should still error
22+
class CC {
23+
value: number = 42;
24+
}
25+
26+
class DD {
27+
test() {
28+
const c = new CC();
29+
if (this === c) { // Should still error - no relationship
30+
console.log("unrelated");
31+
}
32+
}
33+
}
34+
35+
// Test 3: Multiple inheritance levels
36+
class EE extends BB {
37+
getE(): EE { return this; }
38+
}
39+
40+
class FF extends EE {
41+
testMultiLevel() {
42+
const e = new EE();
43+
if (this === e) { // Should not error - FF extends EE
44+
console.log("multi-level inheritance");
45+
}
46+
}
47+
}
48+
49+
// Test 4: Interface implementation
50+
interface ITest {
51+
getValue(): number;
52+
}
53+
54+
class GG implements ITest {
55+
getValue() { return 42; }
56+
57+
testInterface() {
58+
const impl: ITest = new GG();
59+
if (this === impl) { // Should not error
60+
console.log("interface implementation");
61+
}
62+
}
63+
}
64+
65+
//// [thisTypeComparisonExtended.js]
66+
"use strict";
67+
var __extends = (this && this.__extends) || (function () {
68+
var extendStatics = function (d, b) {
69+
extendStatics = Object.setPrototypeOf ||
70+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
71+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
72+
return extendStatics(d, b);
73+
};
74+
return function (d, b) {
75+
if (typeof b !== "function" && b !== null)
76+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
77+
extendStatics(d, b);
78+
function __() { this.constructor = d; }
79+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
80+
};
81+
})();
82+
// Test 1: Original issue - this === subclass instance should work
83+
var AA = /** @class */ (function () {
84+
function AA() {
85+
}
86+
AA.prototype.do1 = function () {
87+
var b = dd.getB();
88+
if (this === b) { // Should not error
89+
console.log("this === b");
90+
}
91+
};
92+
return AA;
93+
}());
94+
var BB = /** @class */ (function (_super) {
95+
__extends(BB, _super);
96+
function BB() {
97+
return _super !== null && _super.apply(this, arguments) || this;
98+
}
99+
BB.prototype.getB = function () { return this; };
100+
return BB;
101+
}(AA));
102+
var dd = new BB();
103+
dd.do1();
104+
// Test 2: this === unrelated class should still error
105+
var CC = /** @class */ (function () {
106+
function CC() {
107+
this.value = 42;
108+
}
109+
return CC;
110+
}());
111+
var DD = /** @class */ (function () {
112+
function DD() {
113+
}
114+
DD.prototype.test = function () {
115+
var c = new CC();
116+
if (this === c) { // Should still error - no relationship
117+
console.log("unrelated");
118+
}
119+
};
120+
return DD;
121+
}());
122+
// Test 3: Multiple inheritance levels
123+
var EE = /** @class */ (function (_super) {
124+
__extends(EE, _super);
125+
function EE() {
126+
return _super !== null && _super.apply(this, arguments) || this;
127+
}
128+
EE.prototype.getE = function () { return this; };
129+
return EE;
130+
}(BB));
131+
var FF = /** @class */ (function (_super) {
132+
__extends(FF, _super);
133+
function FF() {
134+
return _super !== null && _super.apply(this, arguments) || this;
135+
}
136+
FF.prototype.testMultiLevel = function () {
137+
var e = new EE();
138+
if (this === e) { // Should not error - FF extends EE
139+
console.log("multi-level inheritance");
140+
}
141+
};
142+
return FF;
143+
}(EE));
144+
var GG = /** @class */ (function () {
145+
function GG() {
146+
}
147+
GG.prototype.getValue = function () { return 42; };
148+
GG.prototype.testInterface = function () {
149+
var impl = new GG();
150+
if (this === impl) { // Should not error
151+
console.log("interface implementation");
152+
}
153+
};
154+
return GG;
155+
}());

0 commit comments

Comments
 (0)