Skip to content

Commit d85767a

Browse files
authored
fix(60484): Implementing a prim type in a class expression should report error (#60490)
1 parent d6b7c41 commit d85767a

11 files changed

+308
-10
lines changed

src/compiler/checker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3458,10 +3458,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
34583458
if (containerKind === SyntaxKind.InterfaceDeclaration && heritageKind === SyntaxKind.ExtendsKeyword) {
34593459
error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_It_can_only_extend_other_named_object_types, unescapeLeadingUnderscores(name));
34603460
}
3461-
else if (containerKind === SyntaxKind.ClassDeclaration && heritageKind === SyntaxKind.ExtendsKeyword) {
3461+
else if (isClassLike(grandparent.parent) && heritageKind === SyntaxKind.ExtendsKeyword) {
34623462
error(errorLocation, Diagnostics.A_class_cannot_extend_a_primitive_type_like_0_Classes_can_only_extend_constructable_values, unescapeLeadingUnderscores(name));
34633463
}
3464-
else if (containerKind === SyntaxKind.ClassDeclaration && heritageKind === SyntaxKind.ImplementsKeyword) {
3464+
else if (isClassLike(grandparent.parent) && heritageKind === SyntaxKind.ImplementsKeyword) {
34653465
error(errorLocation, Diagnostics.A_class_cannot_implement_a_primitive_type_like_0_It_can_only_implement_other_named_object_types, unescapeLeadingUnderscores(name));
34663466
}
34673467
}

tests/baselines/reference/classExtendingPrimitive.errors.txt

+29-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ classExtendingPrimitive.ts(8,18): error TS2304: Cannot find name 'Null'.
77
classExtendingPrimitive.ts(10,18): error TS2507: Type 'undefined' is not a constructor function type.
88
classExtendingPrimitive.ts(11,18): error TS2552: Cannot find name 'Undefined'. Did you mean 'undefined'?
99
classExtendingPrimitive.ts(14,18): error TS2507: Type 'typeof E' is not a constructor function type.
10+
classExtendingPrimitive.ts(16,26): error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
11+
classExtendingPrimitive.ts(17,27): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
12+
classExtendingPrimitive.ts(18,27): error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
13+
classExtendingPrimitive.ts(20,29): error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
14+
classExtendingPrimitive.ts(21,29): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
15+
classExtendingPrimitive.ts(22,29): error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
1016

1117

12-
==== classExtendingPrimitive.ts (9 errors) ====
18+
==== classExtendingPrimitive.ts (15 errors) ====
1319
// classes cannot extend primitives
1420

1521
class C extends number { }
@@ -41,4 +47,25 @@ classExtendingPrimitive.ts(14,18): error TS2507: Type 'typeof E' is not a constr
4147
enum E { A }
4248
class C8 extends E { }
4349
~
44-
!!! error TS2507: Type 'typeof E' is not a constructor function type.
50+
!!! error TS2507: Type 'typeof E' is not a constructor function type.
51+
52+
const C9 = class extends number { }
53+
~~~~~~
54+
!!! error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
55+
const C10 = class extends string { }
56+
~~~~~~
57+
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
58+
const C11 = class extends boolean { }
59+
~~~~~~~
60+
!!! error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
61+
62+
const C12 = class A extends number { }
63+
~~~~~~
64+
!!! error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
65+
const C13 = class B extends string { }
66+
~~~~~~
67+
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
68+
const C14 = class C extends boolean { }
69+
~~~~~~~
70+
!!! error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
71+

tests/baselines/reference/classExtendingPrimitive.js

+52-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ class C6 extends undefined { }
1414
class C7 extends Undefined { }
1515

1616
enum E { A }
17-
class C8 extends E { }
17+
class C8 extends E { }
18+
19+
const C9 = class extends number { }
20+
const C10 = class extends string { }
21+
const C11 = class extends boolean { }
22+
23+
const C12 = class A extends number { }
24+
const C13 = class B extends string { }
25+
const C14 = class C extends boolean { }
26+
1827

1928
//// [classExtendingPrimitive.js]
2029
// classes cannot extend primitives
@@ -105,3 +114,45 @@ var C8 = /** @class */ (function (_super) {
105114
}
106115
return C8;
107116
}(E));
117+
var C9 = /** @class */ (function (_super) {
118+
__extends(C9, _super);
119+
function C9() {
120+
return _super !== null && _super.apply(this, arguments) || this;
121+
}
122+
return C9;
123+
}(number));
124+
var C10 = /** @class */ (function (_super) {
125+
__extends(C10, _super);
126+
function C10() {
127+
return _super !== null && _super.apply(this, arguments) || this;
128+
}
129+
return C10;
130+
}(string));
131+
var C11 = /** @class */ (function (_super) {
132+
__extends(C11, _super);
133+
function C11() {
134+
return _super !== null && _super.apply(this, arguments) || this;
135+
}
136+
return C11;
137+
}(boolean));
138+
var C12 = /** @class */ (function (_super) {
139+
__extends(A, _super);
140+
function A() {
141+
return _super !== null && _super.apply(this, arguments) || this;
142+
}
143+
return A;
144+
}(number));
145+
var C13 = /** @class */ (function (_super) {
146+
__extends(B, _super);
147+
function B() {
148+
return _super !== null && _super.apply(this, arguments) || this;
149+
}
150+
return B;
151+
}(string));
152+
var C14 = /** @class */ (function (_super) {
153+
__extends(C, _super);
154+
function C() {
155+
return _super !== null && _super.apply(this, arguments) || this;
156+
}
157+
return C;
158+
}(boolean));

tests/baselines/reference/classExtendingPrimitive.symbols

+21
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,24 @@ class C8 extends E { }
3939
>C8 : Symbol(C8, Decl(classExtendingPrimitive.ts, 12, 12))
4040
>E : Symbol(E, Decl(classExtendingPrimitive.ts, 10, 30))
4141

42+
const C9 = class extends number { }
43+
>C9 : Symbol(C9, Decl(classExtendingPrimitive.ts, 15, 5))
44+
45+
const C10 = class extends string { }
46+
>C10 : Symbol(C10, Decl(classExtendingPrimitive.ts, 16, 5))
47+
48+
const C11 = class extends boolean { }
49+
>C11 : Symbol(C11, Decl(classExtendingPrimitive.ts, 17, 5))
50+
51+
const C12 = class A extends number { }
52+
>C12 : Symbol(C12, Decl(classExtendingPrimitive.ts, 19, 5))
53+
>A : Symbol(A, Decl(classExtendingPrimitive.ts, 19, 11))
54+
55+
const C13 = class B extends string { }
56+
>C13 : Symbol(C13, Decl(classExtendingPrimitive.ts, 20, 5))
57+
>B : Symbol(B, Decl(classExtendingPrimitive.ts, 20, 11))
58+
59+
const C14 = class C extends boolean { }
60+
>C14 : Symbol(C14, Decl(classExtendingPrimitive.ts, 21, 5))
61+
>C : Symbol(C, Decl(classExtendingPrimitive.ts, 21, 11))
62+

tests/baselines/reference/classExtendingPrimitive.types

+54
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,57 @@ class C8 extends E { }
6969
>E : typeof E
7070
> : ^^^^^^^^
7171

72+
const C9 = class extends number { }
73+
>C9 : typeof C9
74+
> : ^^^^^^^^^
75+
>class extends number { } : typeof C9
76+
> : ^^^^^^^^^
77+
>number : any
78+
> : ^^^
79+
80+
const C10 = class extends string { }
81+
>C10 : typeof C10
82+
> : ^^^^^^^^^^
83+
>class extends string { } : typeof C10
84+
> : ^^^^^^^^^^
85+
>string : any
86+
> : ^^^
87+
88+
const C11 = class extends boolean { }
89+
>C11 : typeof C11
90+
> : ^^^^^^^^^^
91+
>class extends boolean { } : typeof C11
92+
> : ^^^^^^^^^^
93+
>boolean : any
94+
> : ^^^
95+
96+
const C12 = class A extends number { }
97+
>C12 : typeof A
98+
> : ^^^^^^^^
99+
>class A extends number { } : typeof A
100+
> : ^^^^^^^^
101+
>A : typeof A
102+
> : ^^^^^^^^
103+
>number : any
104+
> : ^^^
105+
106+
const C13 = class B extends string { }
107+
>C13 : typeof B
108+
> : ^^^^^^^^
109+
>class B extends string { } : typeof B
110+
> : ^^^^^^^^
111+
>B : typeof B
112+
> : ^^^^^^^^
113+
>string : any
114+
> : ^^^
115+
116+
const C14 = class C extends boolean { }
117+
>C14 : typeof C
118+
> : ^^^^^^^^
119+
>class C extends boolean { } : typeof C
120+
> : ^^^^^^^^
121+
>C : typeof C
122+
> : ^^^^^^^^
123+
>boolean : any
124+
> : ^^^
125+

tests/baselines/reference/classImplementsPrimitive.errors.txt

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
classImplementsPrimitive.ts(3,20): error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
22
classImplementsPrimitive.ts(4,21): error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
33
classImplementsPrimitive.ts(5,21): error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
4+
classImplementsPrimitive.ts(7,29): error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
5+
classImplementsPrimitive.ts(8,29): error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
6+
classImplementsPrimitive.ts(9,29): error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
7+
classImplementsPrimitive.ts(11,31): error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
8+
classImplementsPrimitive.ts(12,31): error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
9+
classImplementsPrimitive.ts(13,31): error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
410

511

6-
==== classImplementsPrimitive.ts (3 errors) ====
12+
==== classImplementsPrimitive.ts (9 errors) ====
713
// classes cannot implement primitives
814

915
class C implements number { }
@@ -14,4 +20,25 @@ classImplementsPrimitive.ts(5,21): error TS2864: A class cannot implement a prim
1420
!!! error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
1521
class C3 implements boolean { }
1622
~~~~~~~
17-
!!! error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
23+
!!! error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
24+
25+
const C4 = class implements number {}
26+
~~~~~~
27+
!!! error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
28+
const C5 = class implements string {}
29+
~~~~~~
30+
!!! error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
31+
const C6 = class implements boolean {}
32+
~~~~~~~
33+
!!! error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
34+
35+
const C7 = class A implements number { }
36+
~~~~~~
37+
!!! error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
38+
const C8 = class B implements string { }
39+
~~~~~~
40+
!!! error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
41+
const C9 = class C implements boolean { }
42+
~~~~~~~
43+
!!! error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
44+

tests/baselines/reference/classImplementsPrimitive.js

+40-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@
55

66
class C implements number { }
77
class C2 implements string { }
8-
class C3 implements boolean { }
8+
class C3 implements boolean { }
9+
10+
const C4 = class implements number {}
11+
const C5 = class implements string {}
12+
const C6 = class implements boolean {}
13+
14+
const C7 = class A implements number { }
15+
const C8 = class B implements string { }
16+
const C9 = class C implements boolean { }
17+
918

1019
//// [classImplementsPrimitive.js]
1120
// classes cannot implement primitives
@@ -24,3 +33,33 @@ var C3 = /** @class */ (function () {
2433
}
2534
return C3;
2635
}());
36+
var C4 = /** @class */ (function () {
37+
function class_1() {
38+
}
39+
return class_1;
40+
}());
41+
var C5 = /** @class */ (function () {
42+
function class_2() {
43+
}
44+
return class_2;
45+
}());
46+
var C6 = /** @class */ (function () {
47+
function class_3() {
48+
}
49+
return class_3;
50+
}());
51+
var C7 = /** @class */ (function () {
52+
function A() {
53+
}
54+
return A;
55+
}());
56+
var C8 = /** @class */ (function () {
57+
function B() {
58+
}
59+
return B;
60+
}());
61+
var C9 = /** @class */ (function () {
62+
function C() {
63+
}
64+
return C;
65+
}());

tests/baselines/reference/classImplementsPrimitive.symbols

+21
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,24 @@ class C2 implements string { }
1212
class C3 implements boolean { }
1313
>C3 : Symbol(C3, Decl(classImplementsPrimitive.ts, 3, 30))
1414

15+
const C4 = class implements number {}
16+
>C4 : Symbol(C4, Decl(classImplementsPrimitive.ts, 6, 5))
17+
18+
const C5 = class implements string {}
19+
>C5 : Symbol(C5, Decl(classImplementsPrimitive.ts, 7, 5))
20+
21+
const C6 = class implements boolean {}
22+
>C6 : Symbol(C6, Decl(classImplementsPrimitive.ts, 8, 5))
23+
24+
const C7 = class A implements number { }
25+
>C7 : Symbol(C7, Decl(classImplementsPrimitive.ts, 10, 5))
26+
>A : Symbol(A, Decl(classImplementsPrimitive.ts, 10, 10))
27+
28+
const C8 = class B implements string { }
29+
>C8 : Symbol(C8, Decl(classImplementsPrimitive.ts, 11, 5))
30+
>B : Symbol(B, Decl(classImplementsPrimitive.ts, 11, 10))
31+
32+
const C9 = class C implements boolean { }
33+
>C9 : Symbol(C9, Decl(classImplementsPrimitive.ts, 12, 5))
34+
>C : Symbol(C, Decl(classImplementsPrimitive.ts, 12, 10))
35+

tests/baselines/reference/classImplementsPrimitive.types

+42
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,45 @@ class C3 implements boolean { }
1515
>C3 : C3
1616
> : ^^
1717

18+
const C4 = class implements number {}
19+
>C4 : typeof C4
20+
> : ^^^^^^^^^
21+
>class implements number {} : typeof C4
22+
> : ^^^^^^^^^
23+
24+
const C5 = class implements string {}
25+
>C5 : typeof C5
26+
> : ^^^^^^^^^
27+
>class implements string {} : typeof C5
28+
> : ^^^^^^^^^
29+
30+
const C6 = class implements boolean {}
31+
>C6 : typeof C6
32+
> : ^^^^^^^^^
33+
>class implements boolean {} : typeof C6
34+
> : ^^^^^^^^^
35+
36+
const C7 = class A implements number { }
37+
>C7 : typeof A
38+
> : ^^^^^^^^
39+
>class A implements number { } : typeof A
40+
> : ^^^^^^^^
41+
>A : typeof A
42+
> : ^^^^^^^^
43+
44+
const C8 = class B implements string { }
45+
>C8 : typeof B
46+
> : ^^^^^^^^
47+
>class B implements string { } : typeof B
48+
> : ^^^^^^^^
49+
>B : typeof B
50+
> : ^^^^^^^^
51+
52+
const C9 = class C implements boolean { }
53+
>C9 : typeof C
54+
> : ^^^^^^^^
55+
>class C implements boolean { } : typeof C
56+
> : ^^^^^^^^
57+
>C : typeof C
58+
> : ^^^^^^^^
59+

tests/cases/compiler/classImplementsPrimitive.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,12 @@
22

33
class C implements number { }
44
class C2 implements string { }
5-
class C3 implements boolean { }
5+
class C3 implements boolean { }
6+
7+
const C4 = class implements number {}
8+
const C5 = class implements string {}
9+
const C6 = class implements boolean {}
10+
11+
const C7 = class A implements number { }
12+
const C8 = class B implements string { }
13+
const C9 = class C implements boolean { }

0 commit comments

Comments
 (0)