fix(41420): forbid optional chain in extends/implements (#41481)

This commit is contained in:
Oleksandr T 2021-01-05 01:38:54 +02:00 committed by GitHub
parent 6fac3ddfd4
commit b405fdd2ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 180 additions and 2 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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;
}());

View File

@ -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))

View File

@ -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

View File

@ -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.

View File

@ -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 = {}));

View File

@ -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))

View File

@ -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

View File

@ -0,0 +1,9 @@
namespace A {
export class B {}
}
// ok
class C1 extends A?.B {}
// error
class C2 implements A?.B {}

View File

@ -0,0 +1,5 @@
namespace Foo {
export class Bar {}
}
interface C1 extends Foo?.Bar {}