Skip to content

Commit 0648de8

Browse files
TypeScript Bota-tarasyuk
TypeScript Bot
andauthored
Cherry-pick PR #45352 into release-4.4 (#45384)
Component commits: 58a924d fix(45345): throw an error on overridden member that is defined in multiple interfaces Co-authored-by: Oleksandr T <[email protected]>
1 parent c8b1e45 commit 0648de8

File tree

7 files changed

+293
-2
lines changed

7 files changed

+293
-2
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37687,8 +37687,8 @@ namespace ts {
3768737687
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)) :
3768837688
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, baseClassName);
3768937689
}
37690-
else if (prop && baseProp?.valueDeclaration && compilerOptions.noImplicitOverride && !nodeInAmbientContext) {
37691-
const baseHasAbstract = hasAbstractModifier(baseProp.valueDeclaration);
37690+
else if (prop && baseProp?.declarations && compilerOptions.noImplicitOverride && !nodeInAmbientContext) {
37691+
const baseHasAbstract = some(baseProp.declarations, d => hasAbstractModifier(d));
3769237692
if (hasOverride) {
3769337693
return;
3769437694
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
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'.
2+
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'.
3+
4+
5+
==== tests/cases/conformance/override/override20.ts (2 errors) ====
6+
const Foo: C1 & C2 =
7+
class {
8+
m1() { }
9+
m2() { }
10+
}
11+
12+
interface I1 {
13+
m1(): void;
14+
}
15+
16+
interface I2 {
17+
m1(): void;
18+
m2(): void;
19+
}
20+
21+
interface C1 {
22+
new(...args: any[]): I1;
23+
}
24+
25+
interface C2 {
26+
new(...args: any[]): I2;
27+
}
28+
29+
export class Bar extends Foo {
30+
m1() {
31+
~~
32+
!!! error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'I1 & I2'.
33+
super.m1();
34+
}
35+
m2() {
36+
~~
37+
!!! error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'I1 & I2'.
38+
super.m2();
39+
}
40+
}
41+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//// [override20.ts]
2+
const Foo: C1 & C2 =
3+
class {
4+
m1() { }
5+
m2() { }
6+
}
7+
8+
interface I1 {
9+
m1(): void;
10+
}
11+
12+
interface I2 {
13+
m1(): void;
14+
m2(): void;
15+
}
16+
17+
interface C1 {
18+
new(...args: any[]): I1;
19+
}
20+
21+
interface C2 {
22+
new(...args: any[]): I2;
23+
}
24+
25+
export class Bar extends Foo {
26+
m1() {
27+
super.m1();
28+
}
29+
m2() {
30+
super.m2();
31+
}
32+
}
33+
34+
35+
//// [override20.js]
36+
const Foo = class {
37+
m1() { }
38+
m2() { }
39+
};
40+
export class Bar extends Foo {
41+
m1() {
42+
super.m1();
43+
}
44+
m2() {
45+
super.m2();
46+
}
47+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
=== tests/cases/conformance/override/override20.ts ===
2+
const Foo: C1 & C2 =
3+
>Foo : Symbol(Foo, Decl(override20.ts, 0, 5))
4+
>C1 : Symbol(C1, Decl(override20.ts, 13, 1))
5+
>C2 : Symbol(C2, Decl(override20.ts, 17, 1))
6+
7+
class {
8+
m1() { }
9+
>m1 : Symbol(Foo.m1, Decl(override20.ts, 1, 11))
10+
11+
m2() { }
12+
>m2 : Symbol(Foo.m2, Decl(override20.ts, 2, 16))
13+
}
14+
15+
interface I1 {
16+
>I1 : Symbol(I1, Decl(override20.ts, 4, 5))
17+
18+
m1(): void;
19+
>m1 : Symbol(I1.m1, Decl(override20.ts, 6, 14))
20+
}
21+
22+
interface I2 {
23+
>I2 : Symbol(I2, Decl(override20.ts, 8, 1))
24+
25+
m1(): void;
26+
>m1 : Symbol(I2.m1, Decl(override20.ts, 10, 14))
27+
28+
m2(): void;
29+
>m2 : Symbol(I2.m2, Decl(override20.ts, 11, 15))
30+
}
31+
32+
interface C1 {
33+
>C1 : Symbol(C1, Decl(override20.ts, 13, 1))
34+
35+
new(...args: any[]): I1;
36+
>args : Symbol(args, Decl(override20.ts, 16, 8))
37+
>I1 : Symbol(I1, Decl(override20.ts, 4, 5))
38+
}
39+
40+
interface C2 {
41+
>C2 : Symbol(C2, Decl(override20.ts, 17, 1))
42+
43+
new(...args: any[]): I2;
44+
>args : Symbol(args, Decl(override20.ts, 20, 8))
45+
>I2 : Symbol(I2, Decl(override20.ts, 8, 1))
46+
}
47+
48+
export class Bar extends Foo {
49+
>Bar : Symbol(Bar, Decl(override20.ts, 21, 1))
50+
>Foo : Symbol(Foo, Decl(override20.ts, 0, 5))
51+
52+
m1() {
53+
>m1 : Symbol(Bar.m1, Decl(override20.ts, 23, 30))
54+
55+
super.m1();
56+
>super.m1 : Symbol(m1, Decl(override20.ts, 6, 14), Decl(override20.ts, 10, 14))
57+
>m1 : Symbol(m1, Decl(override20.ts, 6, 14), Decl(override20.ts, 10, 14))
58+
}
59+
m2() {
60+
>m2 : Symbol(Bar.m2, Decl(override20.ts, 26, 5))
61+
62+
super.m2();
63+
>super.m2 : Symbol(I2.m2, Decl(override20.ts, 11, 15))
64+
>m2 : Symbol(I2.m2, Decl(override20.ts, 11, 15))
65+
}
66+
}
67+
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
=== tests/cases/conformance/override/override20.ts ===
2+
const Foo: C1 & C2 =
3+
>Foo : C1 & C2
4+
5+
class {
6+
>class { m1() { } m2() { } } : typeof Foo
7+
8+
m1() { }
9+
>m1 : () => void
10+
11+
m2() { }
12+
>m2 : () => void
13+
}
14+
15+
interface I1 {
16+
m1(): void;
17+
>m1 : () => void
18+
}
19+
20+
interface I2 {
21+
m1(): void;
22+
>m1 : () => void
23+
24+
m2(): void;
25+
>m2 : () => void
26+
}
27+
28+
interface C1 {
29+
new(...args: any[]): I1;
30+
>args : any[]
31+
}
32+
33+
interface C2 {
34+
new(...args: any[]): I2;
35+
>args : any[]
36+
}
37+
38+
export class Bar extends Foo {
39+
>Bar : Bar
40+
>Foo : I1 & I2
41+
42+
m1() {
43+
>m1 : () => void
44+
45+
super.m1();
46+
>super.m1() : void
47+
>super.m1 : (() => void) & (() => void)
48+
>super : I1 & I2
49+
>m1 : (() => void) & (() => void)
50+
}
51+
m2() {
52+
>m2 : () => void
53+
54+
super.m2();
55+
>super.m2() : void
56+
>super.m2 : () => void
57+
>super : I1 & I2
58+
>m2 : () => void
59+
}
60+
}
61+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// @target: esnext
2+
// @noImplicitOverride: true
3+
4+
const Foo: C1 & C2 =
5+
class {
6+
m1() { }
7+
m2() { }
8+
}
9+
10+
interface I1 {
11+
m1(): void;
12+
}
13+
14+
interface I2 {
15+
m1(): void;
16+
m2(): void;
17+
}
18+
19+
interface C1 {
20+
new(...args: any[]): I1;
21+
}
22+
23+
interface C2 {
24+
new(...args: any[]): I2;
25+
}
26+
27+
export class Bar extends Foo {
28+
m1() {
29+
super.m1();
30+
}
31+
m2() {
32+
super.m2();
33+
}
34+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @noImplicitOverride: true
4+
5+
////const Foo: C1 & C2 =
6+
//// class {
7+
//// m1() { }
8+
//// m2() { }
9+
//// }
10+
////
11+
////interface I1 {
12+
//// m1(): void;
13+
////}
14+
////
15+
////interface I2 {
16+
//// m1(): void;
17+
//// m2(): void;
18+
////}
19+
////
20+
////interface C1 {
21+
//// new(...args: any[]): I1;
22+
////}
23+
////
24+
////interface C2 {
25+
//// new(...args: any[]): I2;
26+
////}
27+
////
28+
////class Bar extends Foo {
29+
//// [|m1()|] {
30+
//// super.m1();
31+
//// }
32+
//// m2() {
33+
//// super.m2();
34+
//// }
35+
////}
36+
37+
verify.codeFix({
38+
description: "Add 'override' modifier",
39+
newRangeContent: "override m1()",
40+
index: 0
41+
})

0 commit comments

Comments
 (0)