Skip to content

Add conditions to check for class extension or implementation of prim… #55712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3790,8 +3790,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean {
if (meaning & SymbolFlags.Value) {
if (isPrimitiveTypeName(name)) {
if (isExtendedByInterface(errorLocation)) {
error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, unescapeLeadingUnderscores(name));
const grandparent = errorLocation.parent.parent;
if (grandparent && grandparent.parent && isHeritageClause(grandparent)) {
const heritageKind = grandparent.token;
const containerKind = grandparent.parent.kind;
if (containerKind === SyntaxKind.InterfaceDeclaration && heritageKind === SyntaxKind.ExtendsKeyword) {
error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_It_can_only_extend_other_named_object_types, unescapeLeadingUnderscores(name));
}
else if (containerKind === SyntaxKind.ClassDeclaration && heritageKind === SyntaxKind.ExtendsKeyword) {
error(errorLocation, Diagnostics.A_class_cannot_extend_a_primitive_type_like_0_Classes_can_only_extend_constructable_values, unescapeLeadingUnderscores(name));
}
else if (containerKind === SyntaxKind.ClassDeclaration && heritageKind === SyntaxKind.ImplementsKeyword) {
error(errorLocation, Diagnostics.A_class_cannot_implement_a_primitive_type_like_0_It_can_only_implement_other_named_object_types, unescapeLeadingUnderscores(name));
}
}
else {
error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name));
Expand All @@ -3817,17 +3828,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return false;
}

function isExtendedByInterface(node: Node): boolean {
const grandparent = node.parent.parent;
const parentOfGrandparent = grandparent.parent;
if (grandparent && parentOfGrandparent) {
const isExtending = isHeritageClause(grandparent) && grandparent.token === SyntaxKind.ExtendsKeyword;
const isInterface = isInterfaceDeclaration(parentOfGrandparent);
return isExtending && isInterface;
}
return false;
}

function maybeMappedType(node: Node, symbol: Symbol) {
const container = findAncestor(node.parent, n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined;
if (container && container.members.length === 1) {
Expand Down
10 changes: 9 additions & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3619,7 +3619,7 @@
"category": "Error",
"code": 2839
},
"An interface cannot extend a primitive type like '{0}'; an interface can only extend named types and classes": {
"An interface cannot extend a primitive type like '{0}'. It can only extend other named object types.": {
"category": "Error",
"code": 2840
},
Expand Down Expand Up @@ -3703,6 +3703,14 @@
"category": "Error",
"code": 2862
},
"A class cannot extend a primitive type like '{0}'. Classes can only extend constructable values.": {
"category": "Error",
"code": 2863
},
"A class cannot implement a primitive type like '{0}'. It can only implement other named object types.": {
"category": "Error",
"code": 2864
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/classExtendingPrimitive.errors.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
classExtendingPrimitive.ts(3,17): error TS2693: 'number' only refers to a type, but is being used as a value here.
classExtendingPrimitive.ts(4,18): error TS2693: 'string' only refers to a type, but is being used as a value here.
classExtendingPrimitive.ts(5,18): error TS2693: 'boolean' only refers to a type, but is being used as a value here.
classExtendingPrimitive.ts(3,17): error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
classExtendingPrimitive.ts(4,18): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
classExtendingPrimitive.ts(5,18): error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
classExtendingPrimitive.ts(6,18): error TS2304: Cannot find name 'Void'.
classExtendingPrimitive.ts(7,19): error TS1109: Expression expected.
classExtendingPrimitive.ts(8,18): error TS2304: Cannot find name 'Null'.
Expand All @@ -14,13 +14,13 @@ classExtendingPrimitive.ts(14,18): error TS2507: Type 'typeof E' is not a constr

class C extends number { }
~~~~~~
!!! error TS2693: 'number' only refers to a type, but is being used as a value here.
!!! error TS2863: A class cannot extend a primitive type like 'number'. Classes can only extend constructable values.
class C2 extends string { }
~~~~~~
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
class C3 extends boolean { }
~~~~~~~
!!! error TS2693: 'boolean' only refers to a type, but is being used as a value here.
!!! error TS2863: A class cannot extend a primitive type like 'boolean'. Classes can only extend constructable values.
class C4 extends Void { }
~~~~
!!! error TS2304: Cannot find name 'Void'.
Expand Down
17 changes: 17 additions & 0 deletions tests/baselines/reference/classImplementsPrimitive.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
classImplementsPrimitive.ts(3,20): error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
classImplementsPrimitive.ts(4,21): error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
classImplementsPrimitive.ts(5,21): error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.


==== classImplementsPrimitive.ts (3 errors) ====
// classes cannot implement primitives

class C implements number { }
~~~~~~
!!! error TS2864: A class cannot implement a primitive type like 'number'. It can only implement other named object types.
class C2 implements string { }
~~~~~~
!!! error TS2864: A class cannot implement a primitive type like 'string'. It can only implement other named object types.
class C3 implements boolean { }
~~~~~~~
!!! error TS2864: A class cannot implement a primitive type like 'boolean'. It can only implement other named object types.
26 changes: 26 additions & 0 deletions tests/baselines/reference/classImplementsPrimitive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//// [tests/cases/compiler/classImplementsPrimitive.ts] ////

//// [classImplementsPrimitive.ts]
// classes cannot implement primitives

class C implements number { }
class C2 implements string { }
class C3 implements boolean { }

//// [classImplementsPrimitive.js]
// classes cannot implement primitives
var C = /** @class */ (function () {
function C() {
}
return C;
}());
var C2 = /** @class */ (function () {
function C2() {
}
return C2;
}());
var C3 = /** @class */ (function () {
function C3() {
}
return C3;
}());
14 changes: 14 additions & 0 deletions tests/baselines/reference/classImplementsPrimitive.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [tests/cases/compiler/classImplementsPrimitive.ts] ////

=== classImplementsPrimitive.ts ===
// classes cannot implement primitives

class C implements number { }
>C : Symbol(C, Decl(classImplementsPrimitive.ts, 0, 0))

class C2 implements string { }
>C2 : Symbol(C2, Decl(classImplementsPrimitive.ts, 2, 29))

class C3 implements boolean { }
>C3 : Symbol(C3, Decl(classImplementsPrimitive.ts, 3, 30))

14 changes: 14 additions & 0 deletions tests/baselines/reference/classImplementsPrimitive.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [tests/cases/compiler/classImplementsPrimitive.ts] ////

=== classImplementsPrimitive.ts ===
// classes cannot implement primitives

class C implements number { }
>C : C

class C2 implements string { }
>C2 : C2

class C3 implements boolean { }
>C3 : C3

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
errorLocationForInterfaceExtension.ts(3,21): error TS2840: An interface cannot extend a primitive type like 'string'; an interface can only extend named types and classes
errorLocationForInterfaceExtension.ts(3,21): error TS2840: An interface cannot extend a primitive type like 'string'. It can only extend other named object types.


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

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

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


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

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

interface f {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ topLevelAwaitErrors.1.ts(8,14): error TS1005: '>' expected.
topLevelAwaitErrors.1.ts(8,16): error TS2693: 'string' only refers to a type, but is being used as a value here.
topLevelAwaitErrors.1.ts(11,17): error TS1109: Expression expected.
topLevelAwaitErrors.1.ts(11,22): error TS1109: Expression expected.
topLevelAwaitErrors.1.ts(11,23): error TS2693: 'string' only refers to a type, but is being used as a value here.
topLevelAwaitErrors.1.ts(11,23): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
topLevelAwaitErrors.1.ts(11,29): error TS1005: ',' expected.
topLevelAwaitErrors.1.ts(15,8): error TS1109: Expression expected.
topLevelAwaitErrors.1.ts(18,2): error TS1109: Expression expected.
Expand Down Expand Up @@ -49,7 +49,7 @@ topLevelAwaitErrors.1.ts(42,20): error TS1109: Expression expected.
~
!!! error TS1109: Expression expected.
~~~~~~
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
~
!!! error TS1005: ',' expected.
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ topLevelAwaitErrors.1.ts(8,14): error TS1005: '>' expected.
topLevelAwaitErrors.1.ts(8,16): error TS2693: 'string' only refers to a type, but is being used as a value here.
topLevelAwaitErrors.1.ts(11,17): error TS1109: Expression expected.
topLevelAwaitErrors.1.ts(11,22): error TS1109: Expression expected.
topLevelAwaitErrors.1.ts(11,23): error TS2693: 'string' only refers to a type, but is being used as a value here.
topLevelAwaitErrors.1.ts(11,23): error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
topLevelAwaitErrors.1.ts(11,29): error TS1005: ',' expected.
topLevelAwaitErrors.1.ts(15,8): error TS1109: Expression expected.
topLevelAwaitErrors.1.ts(18,2): error TS1109: Expression expected.
Expand Down Expand Up @@ -49,7 +49,7 @@ topLevelAwaitErrors.1.ts(42,20): error TS1109: Expression expected.
~
!!! error TS1109: Expression expected.
~~~~~~
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
!!! error TS2863: A class cannot extend a primitive type like 'string'. Classes can only extend constructable values.
~
!!! error TS1005: ',' expected.
}
Expand Down
5 changes: 5 additions & 0 deletions tests/cases/compiler/classImplementsPrimitive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// classes cannot implement primitives

class C implements number { }
class C2 implements string { }
class C3 implements boolean { }