Skip to content

Commit 598d912

Browse files
qwefgh90sandersn
andauthored
Add conditions to check for class extension or implementation of prim… (#55712)
Co-authored-by: Nathan Shively-Sanders <[email protected]>
1 parent 2432432 commit 598d912

12 files changed

+112
-28
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3790,8 +3790,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
37903790
function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean {
37913791
if (meaning & SymbolFlags.Value) {
37923792
if (isPrimitiveTypeName(name)) {
3793-
if (isExtendedByInterface(errorLocation)) {
3794-
error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, unescapeLeadingUnderscores(name));
3793+
const grandparent = errorLocation.parent.parent;
3794+
if (grandparent && grandparent.parent && isHeritageClause(grandparent)) {
3795+
const heritageKind = grandparent.token;
3796+
const containerKind = grandparent.parent.kind;
3797+
if (containerKind === SyntaxKind.InterfaceDeclaration && heritageKind === SyntaxKind.ExtendsKeyword) {
3798+
error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_It_can_only_extend_other_named_object_types, unescapeLeadingUnderscores(name));
3799+
}
3800+
else if (containerKind === SyntaxKind.ClassDeclaration && heritageKind === SyntaxKind.ExtendsKeyword) {
3801+
error(errorLocation, Diagnostics.A_class_cannot_extend_a_primitive_type_like_0_Classes_can_only_extend_constructable_values, unescapeLeadingUnderscores(name));
3802+
}
3803+
else if (containerKind === SyntaxKind.ClassDeclaration && heritageKind === SyntaxKind.ImplementsKeyword) {
3804+
error(errorLocation, Diagnostics.A_class_cannot_implement_a_primitive_type_like_0_It_can_only_implement_other_named_object_types, unescapeLeadingUnderscores(name));
3805+
}
37953806
}
37963807
else {
37973808
error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name));
@@ -3817,17 +3828,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
38173828
return false;
38183829
}
38193830

3820-
function isExtendedByInterface(node: Node): boolean {
3821-
const grandparent = node.parent.parent;
3822-
const parentOfGrandparent = grandparent.parent;
3823-
if (grandparent && parentOfGrandparent) {
3824-
const isExtending = isHeritageClause(grandparent) && grandparent.token === SyntaxKind.ExtendsKeyword;
3825-
const isInterface = isInterfaceDeclaration(parentOfGrandparent);
3826-
return isExtending && isInterface;
3827-
}
3828-
return false;
3829-
}
3830-
38313831
function maybeMappedType(node: Node, symbol: Symbol) {
38323832
const container = findAncestor(node.parent, n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined;
38333833
if (container && container.members.length === 1) {

src/compiler/diagnosticMessages.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3619,7 +3619,7 @@
36193619
"category": "Error",
36203620
"code": 2839
36213621
},
3622-
"An interface cannot extend a primitive type like '{0}'; an interface can only extend named types and classes": {
3622+
"An interface cannot extend a primitive type like '{0}'. It can only extend other named object types.": {
36233623
"category": "Error",
36243624
"code": 2840
36253625
},
@@ -3703,6 +3703,14 @@
37033703
"category": "Error",
37043704
"code": 2862
37053705
},
3706+
"A class cannot extend a primitive type like '{0}'. Classes can only extend constructable values.": {
3707+
"category": "Error",
3708+
"code": 2863
3709+
},
3710+
"A class cannot implement a primitive type like '{0}'. It can only implement other named object types.": {
3711+
"category": "Error",
3712+
"code": 2864
3713+
},
37063714

37073715
"Import declaration '{0}' is using private name '{1}'.": {
37083716
"category": "Error",

tests/baselines/reference/classExtendingPrimitive.errors.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
classExtendingPrimitive.ts(3,17): error TS2693: 'number' only refers to a type, but is being used as a value here.
2-
classExtendingPrimitive.ts(4,18): error TS2693: 'string' only refers to a type, but is being used as a value here.
3-
classExtendingPrimitive.ts(5,18): error TS2693: 'boolean' only refers to a type, but is being used as a value here.
1+
classExtendingPrimitive.ts(3,17): error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
2+
classExtendingPrimitive.ts(4,18): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
3+
classExtendingPrimitive.ts(5,18): error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
44
classExtendingPrimitive.ts(6,18): error TS2304: Cannot find name 'Void'.
55
classExtendingPrimitive.ts(7,19): error TS1109: Expression expected.
66
classExtendingPrimitive.ts(8,18): error TS2304: Cannot find name 'Null'.
@@ -14,13 +14,13 @@ classExtendingPrimitive.ts(14,18): error TS2507: Type 'typeof E' is not a constr
1414

1515
class C extends number { }
1616
~~~~~~
17-
!!! error TS2693: 'number' only refers to a type, but is being used as a value here.
17+
!!! error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
1818
class C2 extends string { }
1919
~~~~~~
20-
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
20+
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
2121
class C3 extends boolean { }
2222
~~~~~~~
23-
!!! error TS2693: 'boolean' only refers to a type, but is being used as a value here.
23+
!!! error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
2424
class C4 extends Void { }
2525
~~~~
2626
!!! error TS2304: Cannot find name 'Void'.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
classImplementsPrimitive.ts(3,20): error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
2+
classImplementsPrimitive.ts(4,21): error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
3+
classImplementsPrimitive.ts(5,21): error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
4+
5+
6+
==== classImplementsPrimitive.ts (3 errors) ====
7+
// classes cannot implement primitives
8+
9+
class C implements number { }
10+
~~~~~~
11+
!!! error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
12+
class C2 implements string { }
13+
~~~~~~
14+
!!! error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
15+
class C3 implements boolean { }
16+
~~~~~~~
17+
!!! error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [tests/cases/compiler/classImplementsPrimitive.ts] ////
2+
3+
//// [classImplementsPrimitive.ts]
4+
// classes cannot implement primitives
5+
6+
class C implements number { }
7+
class C2 implements string { }
8+
class C3 implements boolean { }
9+
10+
//// [classImplementsPrimitive.js]
11+
// classes cannot implement primitives
12+
var C = /** @class */ (function () {
13+
function C() {
14+
}
15+
return C;
16+
}());
17+
var C2 = /** @class */ (function () {
18+
function C2() {
19+
}
20+
return C2;
21+
}());
22+
var C3 = /** @class */ (function () {
23+
function C3() {
24+
}
25+
return C3;
26+
}());
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [tests/cases/compiler/classImplementsPrimitive.ts] ////
2+
3+
=== classImplementsPrimitive.ts ===
4+
// classes cannot implement primitives
5+
6+
class C implements number { }
7+
>C : Symbol(C, Decl(classImplementsPrimitive.ts, 0, 0))
8+
9+
class C2 implements string { }
10+
>C2 : Symbol(C2, Decl(classImplementsPrimitive.ts, 2, 29))
11+
12+
class C3 implements boolean { }
13+
>C3 : Symbol(C3, Decl(classImplementsPrimitive.ts, 3, 30))
14+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [tests/cases/compiler/classImplementsPrimitive.ts] ////
2+
3+
=== classImplementsPrimitive.ts ===
4+
// classes cannot implement primitives
5+
6+
class C implements number { }
7+
>C : C
8+
9+
class C2 implements string { }
10+
>C2 : C2
11+
12+
class C3 implements boolean { }
13+
>C3 : C3
14+
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
errorLocationForInterfaceExtension.ts(3,21): error TS2840: An interface cannot extend a primitive type like 'string'; an interface can only extend named types and classes
1+
errorLocationForInterfaceExtension.ts(3,21): error TS2840: An interface cannot extend a primitive type like 'string'. It can only extend other named object types.
22

33

44
==== errorLocationForInterfaceExtension.ts (1 errors) ====
55
var n = '';
66

77
interface x extends string { }
88
~~~~~~
9-
!!! error TS2840: An interface cannot extend a primitive type like 'string'; an interface can only extend named types and classes
9+
!!! error TS2840: An interface cannot extend a primitive type like 'string'. It can only extend other named object types.
1010

tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ interfacedeclWithIndexerErrors.ts(14,5): error TS2411: Property 'p4' of type 'nu
33
interfacedeclWithIndexerErrors.ts(15,5): error TS2411: Property 'p5' of type '(s: number) => string' is not assignable to 'string' index type '() => string'.
44
interfacedeclWithIndexerErrors.ts(19,5): error TS2411: Property 'f3' of type '(a: string) => number' is not assignable to 'string' index type '() => string'.
55
interfacedeclWithIndexerErrors.ts(20,5): error TS2411: Property 'f4' of type '(s: number) => string' is not assignable to 'string' index type '() => string'.
6-
interfacedeclWithIndexerErrors.ts(44,21): error TS2840: An interface cannot extend a primitive type like 'number'; an interface can only extend named types and classes
6+
interfacedeclWithIndexerErrors.ts(44,21): error TS2840: An interface cannot extend a primitive type like 'number'. It can only extend other named object types.
77
interfacedeclWithIndexerErrors.ts(48,18): error TS2693: 'string' only refers to a type, but is being used as a value here.
88

99

@@ -63,7 +63,7 @@ interfacedeclWithIndexerErrors.ts(48,18): error TS2693: 'string' only refers to
6363

6464
interface e extends number {
6565
~~~~~~
66-
!!! error TS2840: An interface cannot extend a primitive type like 'number'; an interface can only extend named types and classes
66+
!!! error TS2840: An interface cannot extend a primitive type like 'number'. It can only extend other named object types.
6767
}
6868

6969
interface f {

tests/baselines/reference/topLevelAwaitErrors.1(module=es2022).errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ topLevelAwaitErrors.1.ts(8,14): error TS1005: '>' expected.
66
topLevelAwaitErrors.1.ts(8,16): error TS2693: 'string' only refers to a type, but is being used as a value here.
77
topLevelAwaitErrors.1.ts(11,17): error TS1109: Expression expected.
88
topLevelAwaitErrors.1.ts(11,22): error TS1109: Expression expected.
9-
topLevelAwaitErrors.1.ts(11,23): error TS2693: 'string' only refers to a type, but is being used as a value here.
9+
topLevelAwaitErrors.1.ts(11,23): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
1010
topLevelAwaitErrors.1.ts(11,29): error TS1005: ',' expected.
1111
topLevelAwaitErrors.1.ts(15,8): error TS1109: Expression expected.
1212
topLevelAwaitErrors.1.ts(18,2): error TS1109: Expression expected.
@@ -49,7 +49,7 @@ topLevelAwaitErrors.1.ts(42,20): error TS1109: Expression expected.
4949
~
5050
!!! error TS1109: Expression expected.
5151
~~~~~~
52-
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
52+
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
5353
~
5454
!!! error TS1005: ',' expected.
5555
}

tests/baselines/reference/topLevelAwaitErrors.1(module=esnext).errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ topLevelAwaitErrors.1.ts(8,14): error TS1005: '>' expected.
66
topLevelAwaitErrors.1.ts(8,16): error TS2693: 'string' only refers to a type, but is being used as a value here.
77
topLevelAwaitErrors.1.ts(11,17): error TS1109: Expression expected.
88
topLevelAwaitErrors.1.ts(11,22): error TS1109: Expression expected.
9-
topLevelAwaitErrors.1.ts(11,23): error TS2693: 'string' only refers to a type, but is being used as a value here.
9+
topLevelAwaitErrors.1.ts(11,23): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
1010
topLevelAwaitErrors.1.ts(11,29): error TS1005: ',' expected.
1111
topLevelAwaitErrors.1.ts(15,8): error TS1109: Expression expected.
1212
topLevelAwaitErrors.1.ts(18,2): error TS1109: Expression expected.
@@ -49,7 +49,7 @@ topLevelAwaitErrors.1.ts(42,20): error TS1109: Expression expected.
4949
~
5050
!!! error TS1109: Expression expected.
5151
~~~~~~
52-
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
52+
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
5353
~
5454
!!! error TS1005: ',' expected.
5555
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// classes cannot implement primitives
2+
3+
class C implements number { }
4+
class C2 implements string { }
5+
class C3 implements boolean { }

0 commit comments

Comments
 (0)