diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1f4fb57515e..3fc27bd4f34 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35660,7 +35660,7 @@ namespace ts { const implementedTypeNodes = getEffectiveImplementsTypeNodes(node); if (implementedTypeNodes) { for (const typeRefNode of implementedTypeNodes) { - if (!isEntityNameExpression(typeRefNode.expression)) { + if (!isEntityNameExpression(typeRefNode.expression) || isOptionalChain(typeRefNode.expression)) { error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); } checkTypeReferenceNode(typeRefNode); @@ -36009,7 +36009,7 @@ namespace ts { checkObjectTypeForDuplicateDeclarations(node); } forEach(getInterfaceBaseTypeNodes(node), heritageElement => { - if (!isEntityNameExpression(heritageElement.expression)) { + if (!isEntityNameExpression(heritageElement.expression) || isOptionalChain(heritageElement.expression)) { error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); } checkTypeReferenceNode(heritageElement); diff --git a/tests/baselines/reference/classExtendingOptionalChain.errors.txt b/tests/baselines/reference/classExtendingOptionalChain.errors.txt new file mode 100644 index 00000000000..2f4d321e8f9 --- /dev/null +++ b/tests/baselines/reference/classExtendingOptionalChain.errors.txt @@ -0,0 +1,16 @@ +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. + + +==== tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts (1 errors) ==== + namespace A { + export class B {} + } + + // ok + class C1 extends A?.B {} + + // error + class C2 implements A?.B {} + ~~~~ +!!! error TS2500: A class can only implement an identifier/qualified-name with optional type arguments. + \ No newline at end of file diff --git a/tests/baselines/reference/classExtendingOptionalChain.js b/tests/baselines/reference/classExtendingOptionalChain.js new file mode 100644 index 00000000000..c715a9dedcc --- /dev/null +++ b/tests/baselines/reference/classExtendingOptionalChain.js @@ -0,0 +1,51 @@ +//// [classExtendingOptionalChain.ts] +namespace A { + export class B {} +} + +// ok +class C1 extends A?.B {} + +// error +class C2 implements A?.B {} + + +//// [classExtendingOptionalChain.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var A; +(function (A) { + var B = /** @class */ (function () { + function B() { + } + return B; + }()); + A.B = B; +})(A || (A = {})); +// ok +var C1 = /** @class */ (function (_super) { + __extends(C1, _super); + function C1() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C1; +}((A === null || A === void 0 ? void 0 : A.B))); +// error +var C2 = /** @class */ (function () { + function C2() { + } + return C2; +}()); diff --git a/tests/baselines/reference/classExtendingOptionalChain.symbols b/tests/baselines/reference/classExtendingOptionalChain.symbols new file mode 100644 index 00000000000..2b83fa613dd --- /dev/null +++ b/tests/baselines/reference/classExtendingOptionalChain.symbols @@ -0,0 +1,22 @@ +=== tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts === +namespace A { +>A : Symbol(A, Decl(classExtendingOptionalChain.ts, 0, 0)) + + export class B {} +>B : Symbol(B, Decl(classExtendingOptionalChain.ts, 0, 13)) +} + +// ok +class C1 extends A?.B {} +>C1 : Symbol(C1, Decl(classExtendingOptionalChain.ts, 2, 1)) +>A?.B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13)) +>A : Symbol(A, Decl(classExtendingOptionalChain.ts, 0, 0)) +>B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13)) + +// error +class C2 implements A?.B {} +>C2 : Symbol(C2, Decl(classExtendingOptionalChain.ts, 5, 24)) +>A?.B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13)) +>A : Symbol(A, Decl(classExtendingOptionalChain.ts, 0, 0)) +>B : Symbol(A.B, Decl(classExtendingOptionalChain.ts, 0, 13)) + diff --git a/tests/baselines/reference/classExtendingOptionalChain.types b/tests/baselines/reference/classExtendingOptionalChain.types new file mode 100644 index 00000000000..33a498fcab6 --- /dev/null +++ b/tests/baselines/reference/classExtendingOptionalChain.types @@ -0,0 +1,20 @@ +=== tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts === +namespace A { +>A : typeof A + + export class B {} +>B : B +} + +// ok +class C1 extends A?.B {} +>C1 : C1 +>A?.B : A.B +>A : typeof A +>B : typeof A.B + +// error +class C2 implements A?.B {} +>C2 : C2 +>A : typeof A + diff --git a/tests/baselines/reference/interfaceExtendingOptionalChain.errors.txt b/tests/baselines/reference/interfaceExtendingOptionalChain.errors.txt new file mode 100644 index 00000000000..810dbd4b733 --- /dev/null +++ b/tests/baselines/reference/interfaceExtendingOptionalChain.errors.txt @@ -0,0 +1,12 @@ +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts(5,22): error TS2499: An interface can only extend an identifier/qualified-name with optional type arguments. + + +==== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts (1 errors) ==== + namespace Foo { + export class Bar {} + } + + interface C1 extends Foo?.Bar {} + ~~~~~~~~ +!!! error TS2499: An interface can only extend an identifier/qualified-name with optional type arguments. + \ No newline at end of file diff --git a/tests/baselines/reference/interfaceExtendingOptionalChain.js b/tests/baselines/reference/interfaceExtendingOptionalChain.js new file mode 100644 index 00000000000..5e31589ec94 --- /dev/null +++ b/tests/baselines/reference/interfaceExtendingOptionalChain.js @@ -0,0 +1,18 @@ +//// [interfaceExtendingOptionalChain.ts] +namespace Foo { + export class Bar {} +} + +interface C1 extends Foo?.Bar {} + + +//// [interfaceExtendingOptionalChain.js] +var Foo; +(function (Foo) { + var Bar = /** @class */ (function () { + function Bar() { + } + return Bar; + }()); + Foo.Bar = Bar; +})(Foo || (Foo = {})); diff --git a/tests/baselines/reference/interfaceExtendingOptionalChain.symbols b/tests/baselines/reference/interfaceExtendingOptionalChain.symbols new file mode 100644 index 00000000000..548ae62afa4 --- /dev/null +++ b/tests/baselines/reference/interfaceExtendingOptionalChain.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts === +namespace Foo { +>Foo : Symbol(Foo, Decl(interfaceExtendingOptionalChain.ts, 0, 0)) + + export class Bar {} +>Bar : Symbol(Bar, Decl(interfaceExtendingOptionalChain.ts, 0, 15)) +} + +interface C1 extends Foo?.Bar {} +>C1 : Symbol(C1, Decl(interfaceExtendingOptionalChain.ts, 2, 1)) +>Foo?.Bar : Symbol(Foo.Bar, Decl(interfaceExtendingOptionalChain.ts, 0, 15)) +>Foo : Symbol(Foo, Decl(interfaceExtendingOptionalChain.ts, 0, 0)) +>Bar : Symbol(Foo.Bar, Decl(interfaceExtendingOptionalChain.ts, 0, 15)) + diff --git a/tests/baselines/reference/interfaceExtendingOptionalChain.types b/tests/baselines/reference/interfaceExtendingOptionalChain.types new file mode 100644 index 00000000000..4d3eb2a937d --- /dev/null +++ b/tests/baselines/reference/interfaceExtendingOptionalChain.types @@ -0,0 +1,11 @@ +=== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts === +namespace Foo { +>Foo : typeof Foo + + export class Bar {} +>Bar : Bar +} + +interface C1 extends Foo?.Bar {} +>Foo : typeof Foo + diff --git a/tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts b/tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts new file mode 100644 index 00000000000..261bb09e5ae --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classHeritageSpecification/classExtendingOptionalChain.ts @@ -0,0 +1,9 @@ +namespace A { + export class B {} +} + +// ok +class C1 extends A?.B {} + +// error +class C2 implements A?.B {} diff --git a/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts new file mode 100644 index 00000000000..767f3085d22 --- /dev/null +++ b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceExtendingOptionalChain.ts @@ -0,0 +1,5 @@ +namespace Foo { + export class Bar {} +} + +interface C1 extends Foo?.Bar {}