mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Show error when trying to instantiate a union of abstract and concrete constructors (#48114)
* check composite signatures for abstract flag * add tests and baselines * refactor someSignature into a single function
This commit is contained in:
@@ -30800,7 +30800,7 @@ namespace ts {
|
||||
// then it cannot be instantiated.
|
||||
// In the case of a merged class-module or class-interface declaration,
|
||||
// only the class declaration node will have the Abstract flag set.
|
||||
if (constructSignatures.some(signature => signature.flags & SignatureFlags.Abstract)) {
|
||||
if (someSignature(constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract))) {
|
||||
error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class);
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
@@ -30835,6 +30835,13 @@ namespace ts {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
function someSignature(signatures: Signature | readonly Signature[], f: (s: Signature) => boolean): boolean {
|
||||
if (isArray(signatures)) {
|
||||
return some(signatures, signature => someSignature(signature, f));
|
||||
}
|
||||
return signatures.compositeKind === TypeFlags.Union ? some(signatures.compositeSignatures, f) : f(signatures);
|
||||
}
|
||||
|
||||
function typeHasProtectedAccessibleBase(target: Symbol, type: InterfaceType): boolean {
|
||||
const baseTypes = getBaseTypes(type);
|
||||
if (!length(baseTypes)) {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
tests/cases/compiler/abstractClassUnionInstantiation.ts(14,1): error TS2511: Cannot create an instance of an abstract class.
|
||||
tests/cases/compiler/abstractClassUnionInstantiation.ts(15,1): error TS2511: Cannot create an instance of an abstract class.
|
||||
tests/cases/compiler/abstractClassUnionInstantiation.ts(18,46): error TS2511: Cannot create an instance of an abstract class.
|
||||
tests/cases/compiler/abstractClassUnionInstantiation.ts(19,46): error TS2511: Cannot create an instance of an abstract class.
|
||||
tests/cases/compiler/abstractClassUnionInstantiation.ts(21,35): error TS2511: Cannot create an instance of an abstract class.
|
||||
|
||||
|
||||
==== tests/cases/compiler/abstractClassUnionInstantiation.ts (5 errors) ====
|
||||
class ConcreteA {}
|
||||
class ConcreteB {}
|
||||
abstract class AbstractA { a: string; }
|
||||
abstract class AbstractB { b: string; }
|
||||
|
||||
type Abstracts = typeof AbstractA | typeof AbstractB;
|
||||
type Concretes = typeof ConcreteA | typeof ConcreteB;
|
||||
type ConcretesOrAbstracts = Concretes | Abstracts;
|
||||
|
||||
declare const cls1: ConcretesOrAbstracts;
|
||||
declare const cls2: Abstracts;
|
||||
declare const cls3: Concretes;
|
||||
|
||||
new cls1(); // should error
|
||||
~~~~~~~~~~
|
||||
!!! error TS2511: Cannot create an instance of an abstract class.
|
||||
new cls2(); // should error
|
||||
~~~~~~~~~~
|
||||
!!! error TS2511: Cannot create an instance of an abstract class.
|
||||
new cls3(); // should work
|
||||
|
||||
[ConcreteA, AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
~~~~~~~~~
|
||||
!!! error TS2511: Cannot create an instance of an abstract class.
|
||||
[AbstractA, AbstractB, ConcreteA].map(cls => new cls()); // should error
|
||||
~~~~~~~~~
|
||||
!!! error TS2511: Cannot create an instance of an abstract class.
|
||||
[ConcreteA, ConcreteB].map(cls => new cls()); // should work
|
||||
[AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
~~~~~~~~~
|
||||
!!! error TS2511: Cannot create an instance of an abstract class.
|
||||
@@ -0,0 +1,51 @@
|
||||
//// [abstractClassUnionInstantiation.ts]
|
||||
class ConcreteA {}
|
||||
class ConcreteB {}
|
||||
abstract class AbstractA { a: string; }
|
||||
abstract class AbstractB { b: string; }
|
||||
|
||||
type Abstracts = typeof AbstractA | typeof AbstractB;
|
||||
type Concretes = typeof ConcreteA | typeof ConcreteB;
|
||||
type ConcretesOrAbstracts = Concretes | Abstracts;
|
||||
|
||||
declare const cls1: ConcretesOrAbstracts;
|
||||
declare const cls2: Abstracts;
|
||||
declare const cls3: Concretes;
|
||||
|
||||
new cls1(); // should error
|
||||
new cls2(); // should error
|
||||
new cls3(); // should work
|
||||
|
||||
[ConcreteA, AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
[AbstractA, AbstractB, ConcreteA].map(cls => new cls()); // should error
|
||||
[ConcreteA, ConcreteB].map(cls => new cls()); // should work
|
||||
[AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
|
||||
//// [abstractClassUnionInstantiation.js]
|
||||
var ConcreteA = /** @class */ (function () {
|
||||
function ConcreteA() {
|
||||
}
|
||||
return ConcreteA;
|
||||
}());
|
||||
var ConcreteB = /** @class */ (function () {
|
||||
function ConcreteB() {
|
||||
}
|
||||
return ConcreteB;
|
||||
}());
|
||||
var AbstractA = /** @class */ (function () {
|
||||
function AbstractA() {
|
||||
}
|
||||
return AbstractA;
|
||||
}());
|
||||
var AbstractB = /** @class */ (function () {
|
||||
function AbstractB() {
|
||||
}
|
||||
return AbstractB;
|
||||
}());
|
||||
new cls1(); // should error
|
||||
new cls2(); // should error
|
||||
new cls3(); // should work
|
||||
[ConcreteA, AbstractA, AbstractB].map(function (cls) { return new cls(); }); // should error
|
||||
[AbstractA, AbstractB, ConcreteA].map(function (cls) { return new cls(); }); // should error
|
||||
[ConcreteA, ConcreteB].map(function (cls) { return new cls(); }); // should work
|
||||
[AbstractA, AbstractB].map(function (cls) { return new cls(); }); // should error
|
||||
@@ -0,0 +1,85 @@
|
||||
=== tests/cases/compiler/abstractClassUnionInstantiation.ts ===
|
||||
class ConcreteA {}
|
||||
>ConcreteA : Symbol(ConcreteA, Decl(abstractClassUnionInstantiation.ts, 0, 0))
|
||||
|
||||
class ConcreteB {}
|
||||
>ConcreteB : Symbol(ConcreteB, Decl(abstractClassUnionInstantiation.ts, 0, 18))
|
||||
|
||||
abstract class AbstractA { a: string; }
|
||||
>AbstractA : Symbol(AbstractA, Decl(abstractClassUnionInstantiation.ts, 1, 18))
|
||||
>a : Symbol(AbstractA.a, Decl(abstractClassUnionInstantiation.ts, 2, 26))
|
||||
|
||||
abstract class AbstractB { b: string; }
|
||||
>AbstractB : Symbol(AbstractB, Decl(abstractClassUnionInstantiation.ts, 2, 39))
|
||||
>b : Symbol(AbstractB.b, Decl(abstractClassUnionInstantiation.ts, 3, 26))
|
||||
|
||||
type Abstracts = typeof AbstractA | typeof AbstractB;
|
||||
>Abstracts : Symbol(Abstracts, Decl(abstractClassUnionInstantiation.ts, 3, 39))
|
||||
>AbstractA : Symbol(AbstractA, Decl(abstractClassUnionInstantiation.ts, 1, 18))
|
||||
>AbstractB : Symbol(AbstractB, Decl(abstractClassUnionInstantiation.ts, 2, 39))
|
||||
|
||||
type Concretes = typeof ConcreteA | typeof ConcreteB;
|
||||
>Concretes : Symbol(Concretes, Decl(abstractClassUnionInstantiation.ts, 5, 53))
|
||||
>ConcreteA : Symbol(ConcreteA, Decl(abstractClassUnionInstantiation.ts, 0, 0))
|
||||
>ConcreteB : Symbol(ConcreteB, Decl(abstractClassUnionInstantiation.ts, 0, 18))
|
||||
|
||||
type ConcretesOrAbstracts = Concretes | Abstracts;
|
||||
>ConcretesOrAbstracts : Symbol(ConcretesOrAbstracts, Decl(abstractClassUnionInstantiation.ts, 6, 53))
|
||||
>Concretes : Symbol(Concretes, Decl(abstractClassUnionInstantiation.ts, 5, 53))
|
||||
>Abstracts : Symbol(Abstracts, Decl(abstractClassUnionInstantiation.ts, 3, 39))
|
||||
|
||||
declare const cls1: ConcretesOrAbstracts;
|
||||
>cls1 : Symbol(cls1, Decl(abstractClassUnionInstantiation.ts, 9, 13))
|
||||
>ConcretesOrAbstracts : Symbol(ConcretesOrAbstracts, Decl(abstractClassUnionInstantiation.ts, 6, 53))
|
||||
|
||||
declare const cls2: Abstracts;
|
||||
>cls2 : Symbol(cls2, Decl(abstractClassUnionInstantiation.ts, 10, 13))
|
||||
>Abstracts : Symbol(Abstracts, Decl(abstractClassUnionInstantiation.ts, 3, 39))
|
||||
|
||||
declare const cls3: Concretes;
|
||||
>cls3 : Symbol(cls3, Decl(abstractClassUnionInstantiation.ts, 11, 13))
|
||||
>Concretes : Symbol(Concretes, Decl(abstractClassUnionInstantiation.ts, 5, 53))
|
||||
|
||||
new cls1(); // should error
|
||||
>cls1 : Symbol(cls1, Decl(abstractClassUnionInstantiation.ts, 9, 13))
|
||||
|
||||
new cls2(); // should error
|
||||
>cls2 : Symbol(cls2, Decl(abstractClassUnionInstantiation.ts, 10, 13))
|
||||
|
||||
new cls3(); // should work
|
||||
>cls3 : Symbol(cls3, Decl(abstractClassUnionInstantiation.ts, 11, 13))
|
||||
|
||||
[ConcreteA, AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
>[ConcreteA, AbstractA, AbstractB].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>ConcreteA : Symbol(ConcreteA, Decl(abstractClassUnionInstantiation.ts, 0, 0))
|
||||
>AbstractA : Symbol(AbstractA, Decl(abstractClassUnionInstantiation.ts, 1, 18))
|
||||
>AbstractB : Symbol(AbstractB, Decl(abstractClassUnionInstantiation.ts, 2, 39))
|
||||
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 17, 38))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 17, 38))
|
||||
|
||||
[AbstractA, AbstractB, ConcreteA].map(cls => new cls()); // should error
|
||||
>[AbstractA, AbstractB, ConcreteA].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>AbstractA : Symbol(AbstractA, Decl(abstractClassUnionInstantiation.ts, 1, 18))
|
||||
>AbstractB : Symbol(AbstractB, Decl(abstractClassUnionInstantiation.ts, 2, 39))
|
||||
>ConcreteA : Symbol(ConcreteA, Decl(abstractClassUnionInstantiation.ts, 0, 0))
|
||||
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 18, 38))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 18, 38))
|
||||
|
||||
[ConcreteA, ConcreteB].map(cls => new cls()); // should work
|
||||
>[ConcreteA, ConcreteB].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>ConcreteA : Symbol(ConcreteA, Decl(abstractClassUnionInstantiation.ts, 0, 0))
|
||||
>ConcreteB : Symbol(ConcreteB, Decl(abstractClassUnionInstantiation.ts, 0, 18))
|
||||
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 19, 27))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 19, 27))
|
||||
|
||||
[AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
>[AbstractA, AbstractB].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>AbstractA : Symbol(AbstractA, Decl(abstractClassUnionInstantiation.ts, 1, 18))
|
||||
>AbstractB : Symbol(AbstractB, Decl(abstractClassUnionInstantiation.ts, 2, 39))
|
||||
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 20, 27))
|
||||
>cls : Symbol(cls, Decl(abstractClassUnionInstantiation.ts, 20, 27))
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
=== tests/cases/compiler/abstractClassUnionInstantiation.ts ===
|
||||
class ConcreteA {}
|
||||
>ConcreteA : ConcreteA
|
||||
|
||||
class ConcreteB {}
|
||||
>ConcreteB : ConcreteB
|
||||
|
||||
abstract class AbstractA { a: string; }
|
||||
>AbstractA : AbstractA
|
||||
>a : string
|
||||
|
||||
abstract class AbstractB { b: string; }
|
||||
>AbstractB : AbstractB
|
||||
>b : string
|
||||
|
||||
type Abstracts = typeof AbstractA | typeof AbstractB;
|
||||
>Abstracts : Abstracts
|
||||
>AbstractA : typeof AbstractA
|
||||
>AbstractB : typeof AbstractB
|
||||
|
||||
type Concretes = typeof ConcreteA | typeof ConcreteB;
|
||||
>Concretes : Concretes
|
||||
>ConcreteA : typeof ConcreteA
|
||||
>ConcreteB : typeof ConcreteB
|
||||
|
||||
type ConcretesOrAbstracts = Concretes | Abstracts;
|
||||
>ConcretesOrAbstracts : ConcretesOrAbstracts
|
||||
|
||||
declare const cls1: ConcretesOrAbstracts;
|
||||
>cls1 : ConcretesOrAbstracts
|
||||
|
||||
declare const cls2: Abstracts;
|
||||
>cls2 : Abstracts
|
||||
|
||||
declare const cls3: Concretes;
|
||||
>cls3 : Concretes
|
||||
|
||||
new cls1(); // should error
|
||||
>new cls1() : any
|
||||
>cls1 : ConcretesOrAbstracts
|
||||
|
||||
new cls2(); // should error
|
||||
>new cls2() : any
|
||||
>cls2 : Abstracts
|
||||
|
||||
new cls3(); // should work
|
||||
>new cls3() : ConcreteA | ConcreteB
|
||||
>cls3 : Concretes
|
||||
|
||||
[ConcreteA, AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
>[ConcreteA, AbstractA, AbstractB].map(cls => new cls()) : any[]
|
||||
>[ConcreteA, AbstractA, AbstractB].map : <U>(callbackfn: (value: typeof ConcreteA | typeof AbstractA | typeof AbstractB, index: number, array: (typeof ConcreteA | typeof AbstractA | typeof AbstractB)[]) => U, thisArg?: any) => U[]
|
||||
>[ConcreteA, AbstractA, AbstractB] : (typeof ConcreteA | typeof AbstractA | typeof AbstractB)[]
|
||||
>ConcreteA : typeof ConcreteA
|
||||
>AbstractA : typeof AbstractA
|
||||
>AbstractB : typeof AbstractB
|
||||
>map : <U>(callbackfn: (value: typeof ConcreteA | typeof AbstractA | typeof AbstractB, index: number, array: (typeof ConcreteA | typeof AbstractA | typeof AbstractB)[]) => U, thisArg?: any) => U[]
|
||||
>cls => new cls() : (cls: typeof ConcreteA | typeof AbstractA | typeof AbstractB) => any
|
||||
>cls : typeof ConcreteA | typeof AbstractA | typeof AbstractB
|
||||
>new cls() : any
|
||||
>cls : typeof ConcreteA | typeof AbstractA | typeof AbstractB
|
||||
|
||||
[AbstractA, AbstractB, ConcreteA].map(cls => new cls()); // should error
|
||||
>[AbstractA, AbstractB, ConcreteA].map(cls => new cls()) : any[]
|
||||
>[AbstractA, AbstractB, ConcreteA].map : <U>(callbackfn: (value: typeof ConcreteA | typeof AbstractA | typeof AbstractB, index: number, array: (typeof ConcreteA | typeof AbstractA | typeof AbstractB)[]) => U, thisArg?: any) => U[]
|
||||
>[AbstractA, AbstractB, ConcreteA] : (typeof ConcreteA | typeof AbstractA | typeof AbstractB)[]
|
||||
>AbstractA : typeof AbstractA
|
||||
>AbstractB : typeof AbstractB
|
||||
>ConcreteA : typeof ConcreteA
|
||||
>map : <U>(callbackfn: (value: typeof ConcreteA | typeof AbstractA | typeof AbstractB, index: number, array: (typeof ConcreteA | typeof AbstractA | typeof AbstractB)[]) => U, thisArg?: any) => U[]
|
||||
>cls => new cls() : (cls: typeof ConcreteA | typeof AbstractA | typeof AbstractB) => any
|
||||
>cls : typeof ConcreteA | typeof AbstractA | typeof AbstractB
|
||||
>new cls() : any
|
||||
>cls : typeof ConcreteA | typeof AbstractA | typeof AbstractB
|
||||
|
||||
[ConcreteA, ConcreteB].map(cls => new cls()); // should work
|
||||
>[ConcreteA, ConcreteB].map(cls => new cls()) : ConcreteA[]
|
||||
>[ConcreteA, ConcreteB].map : <U>(callbackfn: (value: typeof ConcreteA, index: number, array: (typeof ConcreteA)[]) => U, thisArg?: any) => U[]
|
||||
>[ConcreteA, ConcreteB] : (typeof ConcreteA)[]
|
||||
>ConcreteA : typeof ConcreteA
|
||||
>ConcreteB : typeof ConcreteB
|
||||
>map : <U>(callbackfn: (value: typeof ConcreteA, index: number, array: (typeof ConcreteA)[]) => U, thisArg?: any) => U[]
|
||||
>cls => new cls() : (cls: typeof ConcreteA) => ConcreteA
|
||||
>cls : typeof ConcreteA
|
||||
>new cls() : ConcreteA
|
||||
>cls : typeof ConcreteA
|
||||
|
||||
[AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
>[AbstractA, AbstractB].map(cls => new cls()) : any[]
|
||||
>[AbstractA, AbstractB].map : <U>(callbackfn: (value: typeof AbstractA | typeof AbstractB, index: number, array: (typeof AbstractA | typeof AbstractB)[]) => U, thisArg?: any) => U[]
|
||||
>[AbstractA, AbstractB] : (typeof AbstractA | typeof AbstractB)[]
|
||||
>AbstractA : typeof AbstractA
|
||||
>AbstractB : typeof AbstractB
|
||||
>map : <U>(callbackfn: (value: typeof AbstractA | typeof AbstractB, index: number, array: (typeof AbstractA | typeof AbstractB)[]) => U, thisArg?: any) => U[]
|
||||
>cls => new cls() : (cls: typeof AbstractA | typeof AbstractB) => any
|
||||
>cls : typeof AbstractA | typeof AbstractB
|
||||
>new cls() : any
|
||||
>cls : typeof AbstractA | typeof AbstractB
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class ConcreteA {}
|
||||
class ConcreteB {}
|
||||
abstract class AbstractA { a: string; }
|
||||
abstract class AbstractB { b: string; }
|
||||
|
||||
type Abstracts = typeof AbstractA | typeof AbstractB;
|
||||
type Concretes = typeof ConcreteA | typeof ConcreteB;
|
||||
type ConcretesOrAbstracts = Concretes | Abstracts;
|
||||
|
||||
declare const cls1: ConcretesOrAbstracts;
|
||||
declare const cls2: Abstracts;
|
||||
declare const cls3: Concretes;
|
||||
|
||||
new cls1(); // should error
|
||||
new cls2(); // should error
|
||||
new cls3(); // should work
|
||||
|
||||
[ConcreteA, AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
[AbstractA, AbstractB, ConcreteA].map(cls => new cls()); // should error
|
||||
[ConcreteA, ConcreteB].map(cls => new cls()); // should work
|
||||
[AbstractA, AbstractB].map(cls => new cls()); // should error
|
||||
Reference in New Issue
Block a user