8000 fix(41420): forbid optional chain in extends/implements (#41481) · typescript-bot/TypeScript@b405fdd · GitHub
[go: up one dir, main page]

Skip to content

Commit b405fdd

Browse files
authored
fix(41420): forbid optional chain in extends/implements (microsoft#41481)
1 parent 6fac3dd commit b405fdd

11 files changed

+180
-2
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35660,7 +35660,7 @@ namespace ts {
3566035660
const implementedTypeNodes = getEffectiveImplementsTypeNodes(node);
3566135661
if (implementedTypeNodes) {
3566235662
for (const typeRefNode of implementedTypeNodes) {
35663-
if (!isEntityNameExpression(typeRefNode.expression)) {
35663+
if (!isEntityNameExpression(typeRefNode.expression) || isOptionalChain(typeRefNode.expression)) {
3566435664
error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments);
3566535665
}
3566635666
checkTypeReferenceNode(typeRefNode);
@@ -36009,7 +36009,7 @@ namespace ts {
3600936009
checkObjectTypeForDuplicateDeclarations(node);
3601036010
}
3601136011
forEach(getInterfaceBaseTypeNodes(node), heritageElement => {
36012-
if (!isEntityNameExpression(heritageElement.expression)) {
36012+
if (!isEntityNameExpression(heritageElement.expression) || isOptionalChain(heritageElement.expression)) {
3601336013
error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments);
3601436014
}
3601536015
checkTypeReferenceNode(heritageElement);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts(9,21): error TS2500: A class can only implement an identifier/qualified-name with optional type arguments.
2+
3+
4+
==== tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts (1 errors) ====
5+
namespace A {
6+
export class B {}
7+
}
8+
9+
// ok
10+
class C1 extends A?.B {}
11+
12+
// error
13+
class C2 implements A?.B {}
14+
~~~~
15+
!!! error TS2500: A class can only implement an identifier/qualified-name with optional type arguments.
16+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//// [classExtendingOptionalChain.ts]
2+
namespace A {
3+
export class B {}
4+
}
5+
6+
// ok
7+
class C1 extends A?.B {}
8+
9+
// error
10+
class C2 implements A?.B {}
11+
12+
13+
//// [classExtendingOptionalChain.js]
14+
var __extends = (this && this.__extends) || (function () {
15+
var extendStatics = function (d, b) {
16+
extendStatics = Object.setPrototypeOf ||
17+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
18+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
19+
return extendStatics(d, b);
20+
};
21+
return function (d, b) {
22+
if (typeof b !== "function" && b !== null)
23+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
24+
extendStatics(d, b);
25+
function __() 67E6 { this.constructor = d; }
26+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
27+
};
28+
})();
29+
var A;
30+
(function (A) {
31+
var B = /** @class */ (function () {
32+
function B() {
33+
}
34+
return B;
35+
}());
36+
A.B = B;
37+
})(A || (A = {}));
38+
// ok
39+
var C1 = /** @class */ (function (_super) {
40+
__extends(C1, _super);
41+
function C1() {
42+
return _super !== null && _super.apply(this, arguments) || this;
43+
}
44+
return C1;
45+
}((A === null || A === void 0 ? void 0 : A.B)));
46+
// error
47+
var C2 = /** @class */ (function () {
48+
function C2() {
49+
}
50+
return C2;
51+
}());
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts ===
2+
namespace A {
3+
>A : Symbol(A, Decl(classExtendingOptionalChain.ts, 0, 0))
4+
5+
export class B {}
6+
>B : Symbol(B, Decl(classExtendingOptionalChain.ts, 0, 13))
7+
}
8+
9+
// ok
10+
class C1 extends A?.B {}
11+
>C1 : Symbol(C1, Decl(classExtendingOptionalChain.ts, 2, 1))
12+
>A?.B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13))
13+
>A : Symbol(A, Decl(classExtendingOptionalChain.ts, 0, 0))
14+
>B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13))
15+
16+
// error
17+
class C2 implements A?.B {}
18+
>C2 : Symbol(C2, Decl(classExtendingOptionalChain.ts, 5, 24))
19+
>A?.B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13))
20+
>A : Symbol(A, Decl(classExtendingOptionalChain.ts, 0, 0))
21+
>B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13))
22+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts ===
2+
namespace A {
3+
>A : typeof A
4+
5+
export class B {}
6+
>B : B
7+
}
8+
9+
// ok
10+
class C1 extends A?.B {}
11+
>C1 : C1
12+
>A?.B : A.B
13+
>A : typeof A
14+
>B : typeof A.B
15+
16+
// error
17+
class C2 implements A?.B {}
18+
>C2 : C2
19+
>A : typeof A
20+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts(5,22): error TS2499: An interface can only extend an identifier/qualified-name with optional type arguments.
2+
3+
4+
==== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts (1 errors) ====
5+
namespace Foo {
6+
export class Bar {}
7+
}
8+
9+
interface C1 extends Foo?.Bar {}
10+
~~~~~~~~
11+
!!! error TS2499: An interface can only extend an identifier/qualified-name with optional type arguments.
12+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//// [interfaceExtendingOptionalChain.ts]
2+
namespace Foo {
3+
export class Bar {}
4+
}
5+
6+
interface C1 extends Foo?.Bar {}
7+
8+
9+
//// [interfaceExtendingOptionalChain.js]
10+
var Foo;
11+
(function (Foo) {
12+
var Bar = /** @class */ (function () {
13+
function Bar() {
14+
}
15+
return Bar;
16+
}());
17+
Foo.Bar = Bar;
18+
})(Foo || (Foo = {}));
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts ===
2+
namespace Foo {
3+
>Foo : Symbol(Foo, Decl(interfaceExtendingOptionalChain.ts, 0, 0))
4+
5+
export class Bar {}
6+
>Bar : Symbol(Bar, Decl(interfaceExtendingOptionalChain.ts, 0, 15))
7+
}
8+
9+
interface C1 extends Foo?.Bar {}
10+
>C1 : Symbol(C1, Decl(interfaceExtendingOptionalChain.ts, 2, 1))
11+
>Foo?.Bar : Symbol(Foo.Bar, Decl(interfaceExtendingOptionalChain.ts, 0, 15))
12+
>Foo : Symbol(Foo, Decl(interfaceExtendingOptionalChain.ts, 0, 0))
13+
>Bar : Symbol(Foo.Bar, Decl(interfaceExtendingOptionalChain.ts, 0, 15))
14+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts ===
2+
namespace Foo {
3+
>Foo : typeof Foo
4+
5+
export class Bar {}
6+
>Bar : Bar
7+
}
8+
9+
interface C1 extends Foo?.Bar {}
10+
>Foo : typeof Foo
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace A {
2+
export class B {}
3+
}
4+
5+
// ok
6+
class C1 extends A?.B {}
7+
8+
// error
9+
class C2 implements A?.B {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace Foo {
2+
export class Bar {}
3+
}
4+
5+
interface C1 extends Foo?.Bar {}

0 commit comments

Comments
 (0)
0