diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts
index 2cec3adb8f5..e82c579a54f 100644
--- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts
+++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts
@@ -14,19 +14,37 @@ namespace ts.codefix {
}
const startPos: number = classDecl.members.pos;
-
+ const classType = checker.getTypeAtLocation(classDecl);
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
-
const result: CodeAction[] = [];
+ const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
+ const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
+
for (const implementedTypeNode of implementedTypeNodes) {
- const implementedType = checker.getTypeFromTypeReference(implementedTypeNode);
+ const implementedType = checker.getTypeFromTypeReference(implementedTypeNode) as InterfaceTypeWithDeclaredMembers;
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
const nonPrivateMembers = implementedTypeSymbols.filter(symbolRefersToNonPrivateMember);
- const insertion = getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
+ let insertion = "";
+
+ if (!hasNumericIndexSignature) {
+ const typeNumericIndexInfo = implementedType.declaredNumberIndexInfo;
+ if (typeNumericIndexInfo) {
+ insertion = checker.indexSignatureToString(typeNumericIndexInfo, SyntaxKind.NumberKeyword, classDecl);
+ }
+ }
+
+ if (!hasStringIndexSignature) {
+ const typeStringIndexInfo = implementedType.declaredStringIndexInfo;
+ if (typeStringIndexInfo) {
+ insertion += checker.indexSignatureToString(typeStringIndexInfo, SyntaxKind.StringKeyword, classDecl);
+ }
+ }
+
+ insertion += getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
const message = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]);
if (insertion) {
pushAction(result, insertion, message);
diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts
index ef0ca1a9a57..4b921c1a81c 100644
--- a/src/services/codefixes/helpers.ts
+++ b/src/services/codefixes/helpers.ts
@@ -5,7 +5,7 @@ namespace ts.codefix {
* Finds members of the resolved type that are missing in the class pointed to by class decl
* and generates source code for the missing members.
* @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for.
- * @returns undefined iff there is no insertion available.
+ * @returns Empty string iff there are no member insertions.
*/
export function getMissingMembersInsertion(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker, newlineChar: string): string {
const classMembers = classDeclaration.symbol.members;
@@ -16,9 +16,12 @@ namespace ts.codefix {
for (const symbol of missingMembers) {
insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar));
}
- return insertion.length > 0 ? insertion : undefined;
+ return insertion;
}
+ /**
+ * @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
+ */
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
// const name = symbol.getName();
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
@@ -28,8 +31,9 @@ namespace ts.codefix {
}
const declaration = declarations[0] as Declaration;
- const name = declaration.name.getText();
+ const name = declaration.name ? declaration.name.getText() : undefined;
const visibility = getVisibilityPrefix(getModifierFlags(declaration));
+
switch (declaration.kind) {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
@@ -77,14 +81,6 @@ namespace ts.codefix {
result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
return result;
- case SyntaxKind.ComputedPropertyName:
- if (hasDynamicName(declaration)) {
- return "";
- }
- throw new Error("Not implemented, computed property name.");
- case SyntaxKind.IndexSignature:
- throw new Error("Not implemented.");
-
default:
return "";
}
diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyLiterals.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyLiterals.ts
index 98f9c978c3d..465f9a5b4f1 100644
--- a/tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyLiterals.ts
+++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyLiterals.ts
@@ -6,7 +6,7 @@
//// [1](): string;
//// [2]: boolean;
//// }
-
+////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesBoth.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesBoth.ts
new file mode 100644
index 00000000000..e47eeb6d5c1
--- /dev/null
+++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesBoth.ts
@@ -0,0 +1,14 @@
+///
+
+
+//// interface I {
+//// [x: number]: I;
+//// [y: string]: I;
+//// }
+////
+//// class C implements I {[| |]}
+
+verify.rangeAfterCodeFix(`
+ [x: number]: I;
+ [y: string]: I;
+`);
\ No newline at end of file
diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesNoFix.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesNoFix.ts
new file mode 100644
index 00000000000..07896b4cdb3
--- /dev/null
+++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesNoFix.ts
@@ -0,0 +1,11 @@
+///
+
+//// interface I4 {
+//// [x: string, y: number]: number;
+//// }
+////
+//// class C implements I {[| |]}
+
+verify.not.codeFixAvailable();
+
+
diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesNumber.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesNumber.ts
new file mode 100644
index 00000000000..0f143442530
--- /dev/null
+++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesNumber.ts
@@ -0,0 +1,12 @@
+///
+
+//// interface I {
+//// [x: number]: I;
+//// }
+////
+//// class C implements I {[|
+//// |]}
+
+verify.rangeAfterCodeFix(`
+ [x: number]: I;
+`);
\ No newline at end of file
diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesString.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesString.ts
new file mode 100644
index 00000000000..37abd751382
--- /dev/null
+++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceIndexSignaturesString.ts
@@ -0,0 +1,11 @@
+///
+
+//// interface I {
+//// [x: string]: number;
+//// }
+////
+//// class C implements I {[| |]}
+
+verify.rangeAfterCodeFix(`
+ [x: string]: number;
+`);
\ No newline at end of file