add missing index signature support

This commit is contained in:
Arthur Ozga 2016-12-08 16:34:15 -08:00
parent c1a41b9f3c
commit 2f51b363bf
7 changed files with 78 additions and 16 deletions

View File

@ -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);

View File

@ -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 "";
}

View File

@ -6,7 +6,7 @@
//// [1](): string;
//// [2]: boolean;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`

View File

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// [x: number]: I;
//// [y: string]: I;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
[x: number]: I;
[y: string]: I;
`);

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I4 {
//// [x: string, y: number]: number;
//// }
////
//// class C implements I {[| |]}
verify.not.codeFixAvailable();

View File

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// [x: number]: I;
//// }
////
//// class C implements I {[|
//// |]}
verify.rangeAfterCodeFix(`
[x: number]: I;
`);

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// [x: string]: number;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
[x: string]: number;
`);