Better errors for indexing gettable/settable values (#26446)

* give suggestions when index signature given

* add tests for noImplicitAny indexing on Object

* remove comments regarding error messages

* recommend set if el is on RHS of assignment else get

* add new baseline tests
This commit is contained in:
Collins Abitekaniza
2019-04-30 08:31:37 -07:00
committed by Ryan Cavanaugh
parent 3ce3cde493
commit 7016d45447
8 changed files with 289 additions and 19 deletions
+36 -1
View File
@@ -10117,7 +10117,13 @@ namespace ts {
}
}
else {
error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectType));
const suggestion = getSuggestionForNonexistentIndexSignature(objectType, accessExpression);
if (suggestion !== undefined) {
error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestion);
}
else {
error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectType));
}
}
}
}
@@ -20186,6 +20192,35 @@ namespace ts {
return suggestion && symbolName(suggestion);
}
function getSuggestionForNonexistentIndexSignature(objectType: Type, expr: ElementAccessExpression): string | undefined {
// check if object type has setter or getter
const hasProp = (name: "set" | "get", argCount = 1) => {
const prop = getPropertyOfObjectType(objectType, <__String>name);
if (prop) {
const s = getSingleCallSignature(getTypeOfSymbol(prop));
if (s && getMinArgumentCount(s) === argCount && typeToString(getTypeAtPosition(s, 0)) === "string") {
return true;
}
}
return false;
};
const suggestedMethod = isAssignmentTarget(expr) ? "set" : "get";
if (!hasProp(suggestedMethod)) {
return undefined;
}
let suggestion = tryGetPropertyAccessOrIdentifierToString(expr);
if (suggestion === undefined) {
suggestion = suggestedMethod;
}
else {
suggestion += "." + suggestedMethod;
}
return suggestion;
}
/**
* Given a name and a list of symbols whose names are *not* equal to the name, return a spelling suggestion if there is one that is close enough.
* Names less than length 3 only check for case-insensitive equality, not levenshtein distance.
+4 -1
View File
@@ -4272,7 +4272,10 @@
"category": "Error",
"code": 7051
},
"Element implicitly has an 'any' type because type '{0}' has no index signature. Did you mean to call '{1}' ?": {
"category": "Error",
"code": 7052
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
+10
View File
@@ -3960,6 +3960,16 @@ namespace ts {
return isPropertyAccessExpression(node) && isEntityNameExpression(node.expression);
}
export function tryGetPropertyAccessOrIdentifierToString(expr: Expression): string | undefined {
if (isPropertyAccessExpression(expr)) {
return tryGetPropertyAccessOrIdentifierToString(expr.expression) + "." + expr.name;
}
if (isIdentifier(expr)) {
return unescapeLeadingUnderscores(expr.escapedText);
}
return undefined;
}
export function isPrototypeAccess(node: Node): node is PropertyAccessExpression {
return isPropertyAccessExpression(node) && node.name.escapedText === "prototype";
}