Skip to content

Commit 2f51b36

Browse files
author
Arthur Ozga
committed
add missing index signature support
1 parent c1a41b9 commit 2f51b36

7 files changed

+78
-16
lines changed

src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,37 @@ namespace ts.codefix {
1414
}
1515

1616
const startPos: number = classDecl.members.pos;
17-
17+
const classType = checker.getTypeAtLocation(classDecl);
1818
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
19-
2019
const result: CodeAction[] = [];
2120

21+
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
22+
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
23+
2224
for (const implementedTypeNode of implementedTypeNodes) {
23-
const implementedType = checker.getTypeFromTypeReference(implementedTypeNode);
25+
const implementedType = checker.getTypeFromTypeReference(implementedTypeNode) as InterfaceTypeWithDeclaredMembers;
2426
// Note that this is ultimately derived from a map indexed by symbol names,
2527
// so duplicates cannot occur.
2628
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
2729
const nonPrivateMembers = implementedTypeSymbols.filter(symbolRefersToNonPrivateMember);
2830

29-
const insertion = getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
31+
let insertion = "";
32+
33+
if (!hasNumericIndexSignature) {
34+
const typeNumericIndexInfo = implementedType.declaredNumberIndexInfo;
35+
if (typeNumericIndexInfo) {
36+
insertion = checker.indexSignatureToString(typeNumericIndexInfo, SyntaxKind.NumberKeyword, classDecl);
37+
}
38+
}
39+
40+
if (!hasStringIndexSignature) {
41+
const typeStringIndexInfo = implementedType.declaredStringIndexInfo;
42+
if (typeStringIndexInfo) {
43+
insertion += checker.indexSignatureToString(typeStringIndexInfo, SyntaxKind.StringKeyword, classDecl);
44+
}
45+
}
46+
47+
insertion += getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
3048
const message = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]);
3149
if (insertion) {
3250
pushAction(result, insertion, message);

src/services/codefixes/helpers.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace ts.codefix {
55
* Finds members of the resolved type that are missing in the class pointed to by class decl
66
* and generates source code for the missing members.
77
* @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for.
8-
* @returns undefined iff there is no insertion available.
8+
* @returns Empty string iff there are no member insertions.
99
*/
1010
export function getMissingMembersInsertion(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker, newlineChar: string): string {
1111
const classMembers = classDeclaration.symbol.members;
@@ -16,9 +16,12 @@ namespace ts.codefix {
1616
for (const symbol of missingMembers) {
1717
insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar));
1818
}
19-
return insertion.length > 0 ? insertion : undefined;
19+
return insertion;
2020
}
2121

22+
/**
23+
* @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
24+
*/
2225
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
2326
// const name = symbol.getName();
2427
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
@@ -28,8 +31,9 @@ namespace ts.codefix {
2831
}
2932

3033
const declaration = declarations[0] as Declaration;
31-
const name = declaration.name.getText();
34+
const name = declaration.name ? declaration.name.getText() : undefined;
3235
const visibility = getVisibilityPrefix(getModifierFlags(declaration));
36+
3337
switch (declaration.kind) {
3438
case SyntaxKind.GetAccessor:
3539
case SyntaxKind.SetAccessor:
@@ -77,14 +81,6 @@ namespace ts.codefix {
7781
result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
7882

7983
return result;
80-
case SyntaxKind.ComputedPropertyName:
81-
if (hasDynamicName(declaration)) {
82-
return "";
83-
}
84-
throw new Error("Not implemented, computed property name.");
85-
case SyntaxKind.IndexSignature:
86-
throw new Error("Not implemented.");
87-
8884
default:
8985
return "";
9086
}

tests/cases/fourslash/codeFixUnImplementedInterfaceComputedPropertyLiterals.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//// [1](): string;
77
//// [2]: boolean;
88
//// }
9-
9+
////
1010
//// class C implements I {[| |]}
1111

1212
verify.rangeAfterCodeFix(`
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
4+
//// interface I {
5+
//// [x: number]: I;
6+
//// [y: string]: I;
7+
//// }
8+
////
9+
//// class C implements I {[| |]}
10+
11+
verify.rangeAfterCodeFix(`
12+
[x: number]: I;
13+
[y: string]: I;
14+
`);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// interface I4 {
4+
//// [x: string, y: number]: number;
5+
//// }
6+
////
7+
//// class C implements I {[| |]}
8+
9+
verify.not.codeFixAvailable();
10+
11+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// interface I {
4+
//// [x: number]: I;
5+
//// }
6+
////
7+
//// class C implements I {[|
8+
//// |]}
9+
10+
verify.rangeAfterCodeFix(`
11+
[x: number]: I;
12+
`);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// interface I {
4+
//// [x: string]: number;
5+
//// }
6+
////
7+
//// class C implements I {[| |]}
8+
9+
verify.rangeAfterCodeFix(`
10+
[x: string]: number;
11+
`);

0 commit comments

Comments
 (0)