Skip to content

Commit 04dc76e

Browse files
authored
Merge pull request microsoft#24442 from Kingwl/fix-implement-interface-with-extends-class
add lookup for extends class when implement interface
2 parents 5e2c7ff + e05d2ba commit 04dc76e

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ namespace ts.codefix {
3232
return Debug.assertDefined(getContainingClass(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false)));
3333
}
3434

35+
function symbolPointsToNonPrivateMember (symbol: Symbol) {
36+
return !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private);
37+
}
38+
3539
function addMissingDeclarations(
3640
checker: TypeChecker,
3741
implementedTypeNode: ExpressionWithTypeArguments,
@@ -40,11 +44,12 @@ namespace ts.codefix {
4044
changeTracker: textChanges.ChangeTracker,
4145
preferences: UserPreferences,
4246
): void {
47+
const maybeHeritageClauseSymbol = getHeritageClauseSymbolTable(classDeclaration, checker);
4348
// Note that this is ultimately derived from a map indexed by symbol names,
4449
// so duplicates cannot occur.
4550
const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType;
4651
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
47-
const nonPrivateMembers = implementedTypeSymbols.filter(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private));
52+
const nonPrivateAndNotExistedInHeritageClauseMembers = implementedTypeSymbols.filter(and(symbolPointsToNonPrivateMember, symbol => !maybeHeritageClauseSymbol.has(symbol.escapedName)));
4853

4954
const classType = checker.getTypeAtLocation(classDeclaration)!;
5055

@@ -55,7 +60,7 @@ namespace ts.codefix {
5560
createMissingIndexSignatureDeclaration(implementedType, IndexKind.String);
5661
}
5762

58-
createMissingMemberNodes(classDeclaration, nonPrivateMembers, checker, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member));
63+
createMissingMemberNodes(classDeclaration, nonPrivateAndNotExistedInHeritageClauseMembers, checker, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member));
5964

6065
function createMissingIndexSignatureDeclaration(type: InterfaceType, kind: IndexKind): void {
6166
const indexInfoOfKind = checker.getIndexInfoOfType(type, kind);
@@ -64,4 +69,12 @@ namespace ts.codefix {
6469
}
6570
}
6671
}
72+
73+
function getHeritageClauseSymbolTable (classDeclaration: ClassLikeDeclaration, checker: TypeChecker): SymbolTable {
74+
const heritageClauseNode = getClassExtendsHeritageClauseElement(classDeclaration);
75+
if (!heritageClauseNode) return createSymbolTable();
76+
const heritageClauseType = checker.getTypeAtLocation(heritageClauseNode) as InterfaceType;
77+
const heritageClauseTypeSymbols = checker.getPropertiesOfType(heritageClauseType);
78+
return createSymbolTable(heritageClauseTypeSymbols.filter(symbolPointsToNonPrivateMember));
79+
}
6780
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// class Base {
4+
//// foo: number;
5+
//// }
6+
////
7+
//// class D extends Base {
8+
//// bar: number;
9+
//// }
10+
////
11+
//// interface I {
12+
//// foo: number;
13+
//// bar: number;
14+
//// baz: number;
15+
//// }
16+
////
17+
//// class C extends D implements I { }
18+
19+
verify.codeFix({
20+
description: "Implement interface 'I'",
21+
newFileContent:
22+
`class Base {
23+
foo: number;
24+
}
25+
26+
class D extends Base {
27+
bar: number;
28+
}
29+
30+
interface I {
31+
foo: number;
32+
bar: number;
33+
baz: number;
34+
}
35+
36+
class C extends D implements I {
37+
baz: number;
38+
}`,
39+
});

0 commit comments

Comments
 (0)