Skip to content

Commit

Permalink
Cherry-pick PR #45352 into release-4.4 (#45384)
Browse files Browse the repository at this point in the history
Component commits:
58a924d fix(45345): throw an error on overridden member that is defined in multiple interfaces

Co-authored-by: Oleksandr T <oleksandr.tarasiuk@outlook.com>
  • Loading branch information
typescript-bot and a-tarasyuk committed Aug 10, 2021
1 parent c8b1e45 commit 0648de8
Show file tree
Hide file tree
Showing 7 changed files with 293 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/compiler/checker.ts
Expand Up @@ -37687,8 +37687,8 @@ namespace ts {
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, baseClassName, symbolToString(suggestion)) :
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, baseClassName);
}
else if (prop && baseProp?.valueDeclaration && compilerOptions.noImplicitOverride && !nodeInAmbientContext) {
const baseHasAbstract = hasAbstractModifier(baseProp.valueDeclaration);
else if (prop && baseProp?.declarations && compilerOptions.noImplicitOverride && !nodeInAmbientContext) {
const baseHasAbstract = some(baseProp.declarations, d => hasAbstractModifier(d));
if (hasOverride) {
return;
}
Expand Down
41 changes: 41 additions & 0 deletions tests/baselines/reference/override20.errors.txt
@@ -0,0 +1,41 @@
tests/cases/conformance/override/override20.ts(25,5): error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'I1 & I2'.
tests/cases/conformance/override/override20.ts(28,5): error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'I1 & I2'.


==== tests/cases/conformance/override/override20.ts (2 errors) ====
const Foo: C1 & C2 =
class {
m1() { }
m2() { }
}

interface I1 {
m1(): void;
}

interface I2 {
m1(): void;
m2(): void;
}

interface C1 {
new(...args: any[]): I1;
}

interface C2 {
new(...args: any[]): I2;
}

export class Bar extends Foo {
m1() {
~~
!!! error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'I1 & I2'.
super.m1();
}
m2() {
~~
!!! error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'I1 & I2'.
super.m2();
}
}

47 changes: 47 additions & 0 deletions tests/baselines/reference/override20.js
@@ -0,0 +1,47 @@
//// [override20.ts]
const Foo: C1 & C2 =
class {
m1() { }
m2() { }
}

interface I1 {
m1(): void;
}

interface I2 {
m1(): void;
m2(): void;
}

interface C1 {
new(...args: any[]): I1;
}

interface C2 {
new(...args: any[]): I2;
}

export class Bar extends Foo {
m1() {
super.m1();
}
m2() {
super.m2();
}
}


//// [override20.js]
const Foo = class {
m1() { }
m2() { }
};
export class Bar extends Foo {
m1() {
super.m1();
}
m2() {
super.m2();
}
}
67 changes: 67 additions & 0 deletions tests/baselines/reference/override20.symbols
@@ -0,0 +1,67 @@
=== tests/cases/conformance/override/override20.ts ===
const Foo: C1 & C2 =
>Foo : Symbol(Foo, Decl(override20.ts, 0, 5))
>C1 : Symbol(C1, Decl(override20.ts, 13, 1))
>C2 : Symbol(C2, Decl(override20.ts, 17, 1))

class {
m1() { }
>m1 : Symbol(Foo.m1, Decl(override20.ts, 1, 11))

m2() { }
>m2 : Symbol(Foo.m2, Decl(override20.ts, 2, 16))
}

interface I1 {
>I1 : Symbol(I1, Decl(override20.ts, 4, 5))

m1(): void;
>m1 : Symbol(I1.m1, Decl(override20.ts, 6, 14))
}

interface I2 {
>I2 : Symbol(I2, Decl(override20.ts, 8, 1))

m1(): void;
>m1 : Symbol(I2.m1, Decl(override20.ts, 10, 14))

m2(): void;
>m2 : Symbol(I2.m2, Decl(override20.ts, 11, 15))
}

interface C1 {
>C1 : Symbol(C1, Decl(override20.ts, 13, 1))

new(...args: any[]): I1;
>args : Symbol(args, Decl(override20.ts, 16, 8))
>I1 : Symbol(I1, Decl(override20.ts, 4, 5))
}

interface C2 {
>C2 : Symbol(C2, Decl(override20.ts, 17, 1))

new(...args: any[]): I2;
>args : Symbol(args, Decl(override20.ts, 20, 8))
>I2 : Symbol(I2, Decl(override20.ts, 8, 1))
}

export class Bar extends Foo {
>Bar : Symbol(Bar, Decl(override20.ts, 21, 1))
>Foo : Symbol(Foo, Decl(override20.ts, 0, 5))

m1() {
>m1 : Symbol(Bar.m1, Decl(override20.ts, 23, 30))

super.m1();
>super.m1 : Symbol(m1, Decl(override20.ts, 6, 14), Decl(override20.ts, 10, 14))
>m1 : Symbol(m1, Decl(override20.ts, 6, 14), Decl(override20.ts, 10, 14))
}
m2() {
>m2 : Symbol(Bar.m2, Decl(override20.ts, 26, 5))

super.m2();
>super.m2 : Symbol(I2.m2, Decl(override20.ts, 11, 15))
>m2 : Symbol(I2.m2, Decl(override20.ts, 11, 15))
}
}

61 changes: 61 additions & 0 deletions tests/baselines/reference/override20.types
@@ -0,0 +1,61 @@
=== tests/cases/conformance/override/override20.ts ===
const Foo: C1 & C2 =
>Foo : C1 & C2

class {
>class { m1() { } m2() { } } : typeof Foo

m1() { }
>m1 : () => void

m2() { }
>m2 : () => void
}

interface I1 {
m1(): void;
>m1 : () => void
}

interface I2 {
m1(): void;
>m1 : () => void

m2(): void;
>m2 : () => void
}

interface C1 {
new(...args: any[]): I1;
>args : any[]
}

interface C2 {
new(...args: any[]): I2;
>args : any[]
}

export class Bar extends Foo {
>Bar : Bar
>Foo : I1 & I2

m1() {
>m1 : () => void

super.m1();
>super.m1() : void
>super.m1 : (() => void) & (() => void)
>super : I1 & I2
>m1 : (() => void) & (() => void)
}
m2() {
>m2 : () => void

super.m2();
>super.m2() : void
>super.m2 : () => void
>super : I1 & I2
>m2 : () => void
}
}

34 changes: 34 additions & 0 deletions tests/cases/conformance/override/override20.ts
@@ -0,0 +1,34 @@
// @target: esnext
// @noImplicitOverride: true

const Foo: C1 & C2 =
class {
m1() { }
m2() { }
}

interface I1 {
m1(): void;
}

interface I2 {
m1(): void;
m2(): void;
}

interface C1 {
new(...args: any[]): I1;
}

interface C2 {
new(...args: any[]): I2;
}

export class Bar extends Foo {
m1() {
super.m1();
}
m2() {
super.m2();
}
}
41 changes: 41 additions & 0 deletions tests/cases/fourslash/codeFixOverrideModifier22.ts
@@ -0,0 +1,41 @@
/// <reference path='fourslash.ts' />

// @noImplicitOverride: true

////const Foo: C1 & C2 =
//// class {
//// m1() { }
//// m2() { }
//// }
////
////interface I1 {
//// m1(): void;
////}
////
////interface I2 {
//// m1(): void;
//// m2(): void;
////}
////
////interface C1 {
//// new(...args: any[]): I1;
////}
////
////interface C2 {
//// new(...args: any[]): I2;
////}
////
////class Bar extends Foo {
//// [|m1()|] {
//// super.m1();
//// }
//// m2() {
//// super.m2();
//// }
////}

verify.codeFix({
description: "Add 'override' modifier",
newRangeContent: "override m1()",
index: 0
})

0 comments on commit 0648de8

Please sign in to comment.