From 472f087e69947368e22c8002576e46c8ddf40178 Mon Sep 17 00:00:00 2001 From: Charles Pierce Date: Tue, 5 Dec 2017 21:18:31 -0800 Subject: [PATCH] Add new error message when class implements class #19793 --- src/compiler/checker.ts | 7 +++++- src/compiler/diagnosticMessages.json | 4 ++++ .../fixClassIncorrectlyImplementsInterface.ts | 3 ++- .../classImplementsClass2.errors.txt | 6 ++--- .../classImplementsClass4.errors.txt | 6 ++--- .../classImplementsClass5.errors.txt | 6 ++--- .../classImplementsClass7.errors.txt | 14 +++++++++++ .../reference/classImplementsClass7.js | 19 +++++++++++++++ .../reference/classImplementsClass7.symbols | 12 ++++++++++ .../reference/classImplementsClass7.types | 12 ++++++++++ ...sImplementsMergedClassInterface.errors.txt | 18 +++++++------- ...endAndImplementTheSameBaseType2.errors.txt | 10 ++++---- .../genericSpecializations2.errors.txt | 24 +++++++++---------- tests/cases/compiler/classImplementsClass7.ts | 5 ++++ 14 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 tests/baselines/reference/classImplementsClass7.errors.txt create mode 100644 tests/baselines/reference/classImplementsClass7.js create mode 100644 tests/baselines/reference/classImplementsClass7.symbols create mode 100644 tests/baselines/reference/classImplementsClass7.types create mode 100644 tests/cases/compiler/classImplementsClass7.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 25d967795a7..70c3ba395d7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22657,7 +22657,12 @@ namespace ts { const t = getTypeFromTypeNode(typeRefNode); if (t !== unknownType) { if (isValidBaseType(t)) { - checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(t, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1); + checkTypeAssignableTo(typeWithThis, + getTypeWithThisArgument(t, type.thisType), + node.name || node, + t.symbol.flags & SymbolFlags.Class ? + Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass : + Diagnostics.Class_0_incorrectly_implements_interface_1); } else { error(typeRefNode, Diagnostics.A_class_may_only_implement_another_class_or_interface); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index fab7583d90c..a224be9e6d9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2276,6 +2276,10 @@ "category": "Error", "code": 2719 }, + "Class '{0}' incorrectly implements class '{1}'. Did you mean to extend '{1}' and inherit its members as a subclass?": { + "category": "Error", + "code": 2720 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index 1a0cf17bbd6..9b400b3bdcf 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -1,7 +1,8 @@ /* @internal */ namespace ts.codefix { registerCodeFix({ - errorCodes: [Diagnostics.Class_0_incorrectly_implements_interface_1.code], + errorCodes: [Diagnostics.Class_0_incorrectly_implements_interface_1.code, + Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code], getCodeActions: getActionForClassLikeIncorrectImplementsInterface }); diff --git a/tests/baselines/reference/classImplementsClass2.errors.txt b/tests/baselines/reference/classImplementsClass2.errors.txt index 49eeed75fe0..4d82142e5ba 100644 --- a/tests/baselines/reference/classImplementsClass2.errors.txt +++ b/tests/baselines/reference/classImplementsClass2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/classImplementsClass2.ts(2,7): error TS2420: Class 'C' incorrectly implements interface 'A'. +tests/cases/compiler/classImplementsClass2.ts(2,7): error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? Property 'foo' is missing in type 'C'. tests/cases/compiler/classImplementsClass2.ts(13,1): error TS2322: Type 'C' is not assignable to type 'C2'. Property 'foo' is missing in type 'C'. @@ -8,8 +8,8 @@ tests/cases/compiler/classImplementsClass2.ts(13,1): error TS2322: Type 'C' is n class A { foo(): number { return 1; } } class C implements A {} // error ~ -!!! error TS2420: Class 'C' incorrectly implements interface 'A'. -!!! error TS2420: Property 'foo' is missing in type 'C'. +!!! error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Property 'foo' is missing in type 'C'. class C2 extends A { foo() { diff --git a/tests/baselines/reference/classImplementsClass4.errors.txt b/tests/baselines/reference/classImplementsClass4.errors.txt index ecc9d6d8582..2ac005ca40a 100644 --- a/tests/baselines/reference/classImplementsClass4.errors.txt +++ b/tests/baselines/reference/classImplementsClass4.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/classImplementsClass4.ts(5,7): error TS2420: Class 'C' incorrectly implements interface 'A'. +tests/cases/compiler/classImplementsClass4.ts(5,7): error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? Property 'x' is missing in type 'C'. tests/cases/compiler/classImplementsClass4.ts(16,1): error TS2322: Type 'C' is not assignable to type 'C2'. Property 'x' is missing in type 'C'. @@ -11,8 +11,8 @@ tests/cases/compiler/classImplementsClass4.ts(16,1): error TS2322: Type 'C' is n } class C implements A { ~ -!!! error TS2420: Class 'C' incorrectly implements interface 'A'. -!!! error TS2420: Property 'x' is missing in type 'C'. +!!! error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'C'. foo() { return 1; } diff --git a/tests/baselines/reference/classImplementsClass5.errors.txt b/tests/baselines/reference/classImplementsClass5.errors.txt index 076120fdbaf..a291da15407 100644 --- a/tests/baselines/reference/classImplementsClass5.errors.txt +++ b/tests/baselines/reference/classImplementsClass5.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/classImplementsClass5.ts(5,7): error TS2420: Class 'C' incorrectly implements interface 'A'. +tests/cases/compiler/classImplementsClass5.ts(5,7): error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? Types have separate declarations of a private property 'x'. tests/cases/compiler/classImplementsClass5.ts(16,1): error TS2322: Type 'C2' is not assignable to type 'C'. Types have separate declarations of a private property 'x'. @@ -13,8 +13,8 @@ tests/cases/compiler/classImplementsClass5.ts(17,1): error TS2322: Type 'C' is n } class C implements A { ~ -!!! error TS2420: Class 'C' incorrectly implements interface 'A'. -!!! error TS2420: Types have separate declarations of a private property 'x'. +!!! error TS2720: Class 'C' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Types have separate declarations of a private property 'x'. private x = 1; foo() { return 1; diff --git a/tests/baselines/reference/classImplementsClass7.errors.txt b/tests/baselines/reference/classImplementsClass7.errors.txt new file mode 100644 index 00000000000..fef48518dc9 --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.errors.txt @@ -0,0 +1,14 @@ +tests/cases/compiler/classImplementsClass7.ts(5,7): error TS2720: Class 'B' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? + Property 'x' is missing in type 'B'. + + +==== tests/cases/compiler/classImplementsClass7.ts (1 errors) ==== + class A { + private x: number; + } + + class B implements A {} + ~ +!!! error TS2720: Class 'B' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'B'. + \ No newline at end of file diff --git a/tests/baselines/reference/classImplementsClass7.js b/tests/baselines/reference/classImplementsClass7.js new file mode 100644 index 00000000000..bbb2fde3391 --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.js @@ -0,0 +1,19 @@ +//// [classImplementsClass7.ts] +class A { + private x: number; +} + +class B implements A {} + + +//// [classImplementsClass7.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function () { + function B() { + } + return B; +}()); diff --git a/tests/baselines/reference/classImplementsClass7.symbols b/tests/baselines/reference/classImplementsClass7.symbols new file mode 100644 index 00000000000..b72e9dc049f --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/classImplementsClass7.ts === +class A { +>A : Symbol(A, Decl(classImplementsClass7.ts, 0, 0)) + + private x: number; +>x : Symbol(A.x, Decl(classImplementsClass7.ts, 0, 9)) +} + +class B implements A {} +>B : Symbol(B, Decl(classImplementsClass7.ts, 2, 1)) +>A : Symbol(A, Decl(classImplementsClass7.ts, 0, 0)) + diff --git a/tests/baselines/reference/classImplementsClass7.types b/tests/baselines/reference/classImplementsClass7.types new file mode 100644 index 00000000000..42def37193c --- /dev/null +++ b/tests/baselines/reference/classImplementsClass7.types @@ -0,0 +1,12 @@ +=== tests/cases/compiler/classImplementsClass7.ts === +class A { +>A : A + + private x: number; +>x : number +} + +class B implements A {} +>B : B +>A : A + diff --git a/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt b/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt index 3e62e72be84..3d2e721a955 100644 --- a/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt +++ b/tests/baselines/reference/classImplementsMergedClassInterface.errors.txt @@ -1,8 +1,8 @@ -tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(9,7): error TS2420: Class 'C2' incorrectly implements interface 'C1'. +tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(9,7): error TS2720: Class 'C2' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? Property 'x' is missing in type 'C2'. -tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(12,7): error TS2420: Class 'C3' incorrectly implements interface 'C1'. +tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(12,7): error TS2720: Class 'C3' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? Property 'y' is missing in type 'C3'. -tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(16,7): error TS2420: Class 'C4' incorrectly implements interface 'C1'. +tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInterface.ts(16,7): error TS2720: Class 'C4' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? Property 'x' is missing in type 'C4'. @@ -17,21 +17,21 @@ tests/cases/conformance/classes/classDeclarations/classImplementsMergedClassInte class C2 implements C1 { // error -- missing x ~~ -!!! error TS2420: Class 'C2' incorrectly implements interface 'C1'. -!!! error TS2420: Property 'x' is missing in type 'C2'. +!!! error TS2720: Class 'C2' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'C2'. } class C3 implements C1 { // error -- missing y ~~ -!!! error TS2420: Class 'C3' incorrectly implements interface 'C1'. -!!! error TS2420: Property 'y' is missing in type 'C3'. +!!! error TS2720: Class 'C3' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? +!!! error TS2720: Property 'y' is missing in type 'C3'. x : number; } class C4 implements C1 { // error -- missing x ~~ -!!! error TS2420: Class 'C4' incorrectly implements interface 'C1'. -!!! error TS2420: Property 'x' is missing in type 'C4'. +!!! error TS2720: Class 'C4' incorrectly implements class 'C1'. Did you mean to extend 'C1' and inherit its members as a subclass? +!!! error TS2720: Property 'x' is missing in type 'C4'. y : number; } diff --git a/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt b/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt index a44c95377dc..799fc7bb8b0 100644 --- a/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt +++ b/tests/baselines/reference/extendAndImplementTheSameBaseType2.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/extendAndImplementTheSameBaseType2.ts(7,7): error TS2420: Class 'D' incorrectly implements interface 'C'. +tests/cases/compiler/extendAndImplementTheSameBaseType2.ts(7,7): error TS2720: Class 'D' incorrectly implements class 'C'. Did you mean to extend 'C' and inherit its members as a subclass? Types of property 'bar' are incompatible. Type '() => string' is not assignable to type '() => number'. Type 'string' is not assignable to type 'number'. @@ -15,10 +15,10 @@ tests/cases/compiler/extendAndImplementTheSameBaseType2.ts(16,5): error TS2322: } class D extends C implements C { ~ -!!! error TS2420: Class 'D' incorrectly implements interface 'C'. -!!! error TS2420: Types of property 'bar' are incompatible. -!!! error TS2420: Type '() => string' is not assignable to type '() => number'. -!!! error TS2420: Type 'string' is not assignable to type 'number'. +!!! error TS2720: Class 'D' incorrectly implements class 'C'. Did you mean to extend 'C' and inherit its members as a subclass? +!!! error TS2720: Types of property 'bar' are incompatible. +!!! error TS2720: Type '() => string' is not assignable to type '() => number'. +!!! error TS2720: Type 'string' is not assignable to type 'number'. baz() { } } diff --git a/tests/baselines/reference/genericSpecializations2.errors.txt b/tests/baselines/reference/genericSpecializations2.errors.txt index e570adb7912..99a6e2a6985 100644 --- a/tests/baselines/reference/genericSpecializations2.errors.txt +++ b/tests/baselines/reference/genericSpecializations2.errors.txt @@ -1,10 +1,10 @@ -tests/cases/compiler/genericSpecializations2.ts(7,7): error TS2420: Class 'IntFooBad' incorrectly implements interface 'IFoo'. +tests/cases/compiler/genericSpecializations2.ts(7,7): error TS2720: Class 'IntFooBad' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? Types of property 'foo' are incompatible. Type '(x: string) => string' is not assignable to type '(x: T) => T'. Types of parameters 'x' and 'x' are incompatible. Type 'T' is not assignable to type 'string'. tests/cases/compiler/genericSpecializations2.ts(8,9): error TS2368: Type parameter name cannot be 'string'. -tests/cases/compiler/genericSpecializations2.ts(11,7): error TS2420: Class 'StringFoo2' incorrectly implements interface 'IFoo'. +tests/cases/compiler/genericSpecializations2.ts(11,7): error TS2720: Class 'StringFoo2' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? Types of property 'foo' are incompatible. Type '(x: string) => string' is not assignable to type '(x: T) => T'. Types of parameters 'x' and 'x' are incompatible. @@ -21,11 +21,11 @@ tests/cases/compiler/genericSpecializations2.ts(12,9): error TS2368: Type parame class IntFooBad implements IFoo { ~~~~~~~~~ -!!! error TS2420: Class 'IntFooBad' incorrectly implements interface 'IFoo'. -!!! error TS2420: Types of property 'foo' are incompatible. -!!! error TS2420: Type '(x: string) => string' is not assignable to type '(x: T) => T'. -!!! error TS2420: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2420: Type 'T' is not assignable to type 'string'. +!!! error TS2720: Class 'IntFooBad' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? +!!! error TS2720: Types of property 'foo' are incompatible. +!!! error TS2720: Type '(x: string) => string' is not assignable to type '(x: T) => T'. +!!! error TS2720: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2720: Type 'T' is not assignable to type 'string'. foo(x: string): string { return null; } ~~~~~~ !!! error TS2368: Type parameter name cannot be 'string'. @@ -33,11 +33,11 @@ tests/cases/compiler/genericSpecializations2.ts(12,9): error TS2368: Type parame class StringFoo2 implements IFoo { ~~~~~~~~~~ -!!! error TS2420: Class 'StringFoo2' incorrectly implements interface 'IFoo'. -!!! error TS2420: Types of property 'foo' are incompatible. -!!! error TS2420: Type '(x: string) => string' is not assignable to type '(x: T) => T'. -!!! error TS2420: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2420: Type 'T' is not assignable to type 'string'. +!!! error TS2720: Class 'StringFoo2' incorrectly implements class 'IFoo'. Did you mean to extend 'IFoo' and inherit its members as a subclass? +!!! error TS2720: Types of property 'foo' are incompatible. +!!! error TS2720: Type '(x: string) => string' is not assignable to type '(x: T) => T'. +!!! error TS2720: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2720: Type 'T' is not assignable to type 'string'. foo(x: string): string { return null; } ~~~~~~ !!! error TS2368: Type parameter name cannot be 'string'. diff --git a/tests/cases/compiler/classImplementsClass7.ts b/tests/cases/compiler/classImplementsClass7.ts new file mode 100644 index 00000000000..ab56cae56ce --- /dev/null +++ b/tests/cases/compiler/classImplementsClass7.ts @@ -0,0 +1,5 @@ +class A { + private x: number; +} + +class B implements A {}