From e49b841b4d74b390df0bd3a7471f1cc5913d9d89 Mon Sep 17 00:00:00 2001 From: Collins Abitekaniza Date: Tue, 30 Apr 2019 02:08:50 +0300 Subject: [PATCH 1/5] give suggestions when index signature given --- src/compiler/checker.ts | 27 ++++++++++++++++++++++++++- src/compiler/diagnosticMessages.json | 5 ++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 55b364c20101e..5bce4cf61e595 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 suggestions = getSuggestionsForNonexistentIndexSignature(objectType); + if (suggestions) { + error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestions); + } + else { + error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectType)); + } } } } @@ -20186,6 +20192,25 @@ namespace ts { return suggestion && symbolName(suggestion); } + function getSuggestionsForNonexistentIndexSignature(objectType: Type): string | undefined { + let suggestions: string | undefined; + const props = [ + getPropertyOfObjectType(objectType, <__String>"get"), + getPropertyOfObjectType(objectType, <__String>"set") + ]; + + for (const prop of props) { + if (prop) { + const s = getSingleCallSignature(getTypeOfSymbol(prop)); + if (s && getMinArgumentCount(s) === 1 && typeToString(getTypeAtPosition(s, 0)) === "string") { + const suggestion = symbolToString(objectType.symbol) + "." + symbolToString(prop); + suggestions = (!suggestions) ? suggestion : suggestions.concat(" or " + suggestion); + } + } + } + return suggestions; + } + /** * 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. diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 45ec2a9ad427a..b754dbd9ea14b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -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 From b66fea6e4c9fdf608311305daff0a531fc5a7d05 Mon Sep 17 00:00:00 2001 From: Collins Abitekaniza Date: Tue, 30 Apr 2019 02:09:06 +0300 Subject: [PATCH 2/5] add tests for noImplicitAny indexing on Object --- ...mplicitAnyStringIndexerOnObject.errors.txt | 35 +++++++++- .../noImplicitAnyStringIndexerOnObject.js | 44 +++++++++++-- ...noImplicitAnyStringIndexerOnObject.symbols | 48 ++++++++++++-- .../noImplicitAnyStringIndexerOnObject.types | 65 +++++++++++++++++-- .../noImplicitAnyStringIndexerOnObject.ts | 23 ++++++- 5 files changed, 198 insertions(+), 17 deletions(-) diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt index b3f3b4bc6e050..e49b552958e3c 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt @@ -1,8 +1,37 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(1,9): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(8,1): error TS7043: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'c.get' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(14,1): error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. Did you mean to call 'd.set' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(21,1): error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'e.get or e.set' ? -==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (1 errors) ==== - var x = {}["hello"]; +==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (4 errors) ==== + var a = {}["hello"]; ~~~~~~~~~~~ !!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. - var y: string = { '': 'foo' }['']; \ No newline at end of file + var b: string = { '': 'foo' }['']; + + // Should give suggestion 'c.get' + var c = { + get: (key: string) => 'foobar' + }; + c['hello']; + ~~~~~~~~~~ +!!! error TS7043: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'c.get' ? + + // Should give suggestion 'd.set' + var d = { + set: (key: string) => 'foobar' + }; + d['hello']; + ~~~~~~~~~~ +!!! error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. Did you mean to call 'd.set' ? + + // Should give suggestion 'e.get or e.set' + var e = { + set: (key: string) => 'foobar', + get: (key: string) => 'foobar' + }; + e['hello']; + ~~~~~~~~~~ +!!! error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'e.get or e.set' ? + \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js index 2ea3291e5db7a..7ccf474550740 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js @@ -1,7 +1,43 @@ //// [noImplicitAnyStringIndexerOnObject.ts] -var x = {}["hello"]; -var y: string = { '': 'foo' }['']; +var a = {}["hello"]; +var b: string = { '': 'foo' }['']; + +// Should give suggestion 'c.get' +var c = { + get: (key: string) => 'foobar' +}; +c['hello']; + +// Should give suggestion 'd.set' +var d = { + set: (key: string) => 'foobar' +}; +d['hello']; + +// Should give suggestion 'e.get or e.set' +var e = { + set: (key: string) => 'foobar', + get: (key: string) => 'foobar' +}; +e['hello']; + //// [noImplicitAnyStringIndexerOnObject.js] -var x = {}["hello"]; -var y = { '': 'foo' }['']; +var a = {}["hello"]; +var b = { '': 'foo' }['']; +// Should give suggestion 'c.get' +var c = { + get: function (key) { return 'foobar'; } +}; +c['hello']; +// Should give suggestion 'd.set' +var d = { + set: function (key) { return 'foobar'; } +}; +d['hello']; +// Should give suggestion 'e.get or e.set' +var e = { + set: function (key) { return 'foobar'; }, + get: function (key) { return 'foobar'; } +}; +e['hello']; diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols index aa3990b0d7c62..280f0784430a9 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols @@ -1,9 +1,49 @@ === tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts === -var x = {}["hello"]; ->x : Symbol(x, Decl(noImplicitAnyStringIndexerOnObject.ts, 0, 3)) +var a = {}["hello"]; +>a : Symbol(a, Decl(noImplicitAnyStringIndexerOnObject.ts, 0, 3)) -var y: string = { '': 'foo' }['']; ->y : Symbol(y, Decl(noImplicitAnyStringIndexerOnObject.ts, 1, 3)) +var b: string = { '': 'foo' }['']; +>b : Symbol(b, Decl(noImplicitAnyStringIndexerOnObject.ts, 1, 3)) >'' : Symbol('', Decl(noImplicitAnyStringIndexerOnObject.ts, 1, 17)) >'' : Symbol('', Decl(noImplicitAnyStringIndexerOnObject.ts, 1, 17)) +// Should give suggestion 'c.get' +var c = { +>c : Symbol(c, Decl(noImplicitAnyStringIndexerOnObject.ts, 4, 3)) + + get: (key: string) => 'foobar' +>get : Symbol(get, Decl(noImplicitAnyStringIndexerOnObject.ts, 4, 9)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 5, 8)) + +}; +c['hello']; +>c : Symbol(c, Decl(noImplicitAnyStringIndexerOnObject.ts, 4, 3)) + +// Should give suggestion 'd.set' +var d = { +>d : Symbol(d, Decl(noImplicitAnyStringIndexerOnObject.ts, 10, 3)) + + set: (key: string) => 'foobar' +>set : Symbol(set, Decl(noImplicitAnyStringIndexerOnObject.ts, 10, 9)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 11, 8)) + +}; +d['hello']; +>d : Symbol(d, Decl(noImplicitAnyStringIndexerOnObject.ts, 10, 3)) + +// Should give suggestion 'e.get or e.set' +var e = { +>e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 16, 3)) + + set: (key: string) => 'foobar', +>set : Symbol(set, Decl(noImplicitAnyStringIndexerOnObject.ts, 16, 9)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 17, 8)) + + get: (key: string) => 'foobar' +>get : Symbol(get, Decl(noImplicitAnyStringIndexerOnObject.ts, 17, 33)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 18, 8)) + +}; +e['hello']; +>e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 16, 3)) + diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types index a1b78eaca57da..20b517497d245 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types @@ -1,15 +1,72 @@ === tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts === -var x = {}["hello"]; ->x : any +var a = {}["hello"]; +>a : any >{}["hello"] : any >{} : {} >"hello" : "hello" -var y: string = { '': 'foo' }['']; ->y : string +var b: string = { '': 'foo' }['']; +>b : string >{ '': 'foo' }[''] : string >{ '': 'foo' } : { '': string; } >'' : string >'foo' : "foo" >'' : "" +// Should give suggestion 'c.get' +var c = { +>c : { get: (key: string) => string; } +>{ get: (key: string) => 'foobar'} : { get: (key: string) => string; } + + get: (key: string) => 'foobar' +>get : (key: string) => string +>(key: string) => 'foobar' : (key: string) => string +>key : string +>'foobar' : "foobar" + +}; +c['hello']; +>c['hello'] : any +>c : { get: (key: string) => string; } +>'hello' : "hello" + +// Should give suggestion 'd.set' +var d = { +>d : { set: (key: string) => string; } +>{ set: (key: string) => 'foobar'} : { set: (key: string) => string; } + + set: (key: string) => 'foobar' +>set : (key: string) => string +>(key: string) => 'foobar' : (key: string) => string +>key : string +>'foobar' : "foobar" + +}; +d['hello']; +>d['hello'] : any +>d : { set: (key: string) => string; } +>'hello' : "hello" + +// Should give suggestion 'e.get or e.set' +var e = { +>e : { set: (key: string) => string; get: (key: string) => string; } +>{ set: (key: string) => 'foobar', get: (key: string) => 'foobar'} : { set: (key: string) => string; get: (key: string) => string; } + + set: (key: string) => 'foobar', +>set : (key: string) => string +>(key: string) => 'foobar' : (key: string) => string +>key : string +>'foobar' : "foobar" + + get: (key: string) => 'foobar' +>get : (key: string) => string +>(key: string) => 'foobar' : (key: string) => string +>key : string +>'foobar' : "foobar" + +}; +e['hello']; +>e['hello'] : any +>e : { set: (key: string) => string; get: (key: string) => string; } +>'hello' : "hello" + diff --git a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts index 9a84cc328b286..d35edbd793488 100644 --- a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts +++ b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts @@ -1,4 +1,23 @@ // @noimplicitany: true -var x = {}["hello"]; -var y: string = { '': 'foo' }['']; \ No newline at end of file +var a = {}["hello"]; +var b: string = { '': 'foo' }['']; + +// Should give suggestion 'c.get' +var c = { + get: (key: string) => 'foobar' +}; +c['hello']; + +// Should give suggestion 'd.set' +var d = { + set: (key: string) => 'foobar' +}; +d['hello']; + +// Should give suggestion 'e.get or e.set' +var e = { + set: (key: string) => 'foobar', + get: (key: string) => 'foobar' +}; +e['hello']; From a481be729ac183b74f186dbb82310f642f323fe9 Mon Sep 17 00:00:00 2001 From: Collins Abitekaniza Date: Tue, 30 Apr 2019 02:09:17 +0300 Subject: [PATCH 3/5] remove comments regarding error messages --- tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts index d35edbd793488..e627134bf6720 100644 --- a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts +++ b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts @@ -3,19 +3,16 @@ var a = {}["hello"]; var b: string = { '': 'foo' }['']; -// Should give suggestion 'c.get' var c = { get: (key: string) => 'foobar' }; c['hello']; -// Should give suggestion 'd.set' var d = { set: (key: string) => 'foobar' }; d['hello']; -// Should give suggestion 'e.get or e.set' var e = { set: (key: string) => 'foobar', get: (key: string) => 'foobar' From 5256ff74457ce6a618fcd750cc46d69c4c97ddc0 Mon Sep 17 00:00:00 2001 From: Collins Abitekaniza Date: Tue, 30 Apr 2019 02:09:29 +0300 Subject: [PATCH 4/5] recommend set if el is on RHS of assignment else get --- src/compiler/checker.ts | 40 ++++++++++++++++++++++++--------------- src/compiler/utilities.ts | 10 ++++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5bce4cf61e595..fa02cb4ea37b0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10117,9 +10117,9 @@ namespace ts { } } else { - const suggestions = getSuggestionsForNonexistentIndexSignature(objectType); - if (suggestions) { - error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestions); + 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)); @@ -20192,23 +20192,33 @@ namespace ts { return suggestion && symbolName(suggestion); } - function getSuggestionsForNonexistentIndexSignature(objectType: Type): string | undefined { - let suggestions: string | undefined; - const props = [ - getPropertyOfObjectType(objectType, <__String>"get"), - getPropertyOfObjectType(objectType, <__String>"set") - ]; - - for (const prop of props) { + 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) === 1 && typeToString(getTypeAtPosition(s, 0)) === "string") { - const suggestion = symbolToString(objectType.symbol) + "." + symbolToString(prop); - suggestions = (!suggestions) ? suggestion : suggestions.concat(" or " + suggestion); + 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; } - return suggestions; + else { + suggestion += "." + suggestedMethod; + } + + return suggestion; } /** diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 188f2f8630209..45dc980296be7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -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"; } From cab6e04ce1a9d7d255aa227bd9dbf6582425a013 Mon Sep 17 00:00:00 2001 From: Collins Abitekaniza Date: Tue, 30 Apr 2019 02:29:06 +0300 Subject: [PATCH 5/5] add new baseline tests --- ...mplicitAnyStringIndexerOnObject.errors.txt | 36 +++++++++----- .../noImplicitAnyStringIndexerOnObject.js | 21 +++++---- ...noImplicitAnyStringIndexerOnObject.symbols | 47 +++++++++++-------- .../noImplicitAnyStringIndexerOnObject.types | 30 ++++++++++-- .../noImplicitAnyStringIndexerOnObject.ts | 8 +++- 5 files changed, 93 insertions(+), 49 deletions(-) diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt index e49b552958e3c..6df52aea46a88 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt @@ -1,37 +1,47 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(1,9): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(8,1): error TS7043: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'c.get' ? -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(14,1): error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. Did you mean to call 'd.set' ? -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(21,1): error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'e.get or e.set' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(7,1): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'get' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(8,13): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'get' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(13,13): error TS7017: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(19,1): error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(20,1): error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(21,1): error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? -==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (4 errors) ==== +==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (7 errors) ==== var a = {}["hello"]; ~~~~~~~~~~~ !!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. var b: string = { '': 'foo' }['']; - // Should give suggestion 'c.get' var c = { get: (key: string) => 'foobar' }; c['hello']; ~~~~~~~~~~ -!!! error TS7043: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'c.get' ? +!!! error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'get' ? + const foo = c['hello']; + ~~~~~~~~~~ +!!! error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; }' has no index signature. Did you mean to call 'get' ? - // Should give suggestion 'd.set' var d = { set: (key: string) => 'foobar' }; - d['hello']; - ~~~~~~~~~~ -!!! error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. Did you mean to call 'd.set' ? + const bar = d['hello']; + ~~~~~~~~~~ +!!! error TS7017: Element implicitly has an 'any' type because type '{ set: (key: string) => string; }' has no index signature. - // Should give suggestion 'e.get or e.set' var e = { set: (key: string) => 'foobar', get: (key: string) => 'foobar' }; - e['hello']; + e['hello'] = 'modified'; + ~~~~~~~~~~ +!!! error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? + e['hello'] += 1; ~~~~~~~~~~ -!!! error TS7043: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'e.get or e.set' ? +!!! error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? + e['hello'] ++; + ~~~~~~~~~~ +!!! error TS7052: Element implicitly has an 'any' type because type '{ set: (key: string) => string; get: (key: string) => string; }' has no index signature. Did you mean to call 'set' ? + \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js index 7ccf474550740..a02740351cff5 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.js @@ -2,42 +2,43 @@ var a = {}["hello"]; var b: string = { '': 'foo' }['']; -// Should give suggestion 'c.get' var c = { get: (key: string) => 'foobar' }; c['hello']; +const foo = c['hello']; -// Should give suggestion 'd.set' var d = { set: (key: string) => 'foobar' }; -d['hello']; +const bar = d['hello']; -// Should give suggestion 'e.get or e.set' var e = { set: (key: string) => 'foobar', get: (key: string) => 'foobar' }; -e['hello']; +e['hello'] = 'modified'; +e['hello'] += 1; +e['hello'] ++; + //// [noImplicitAnyStringIndexerOnObject.js] var a = {}["hello"]; var b = { '': 'foo' }['']; -// Should give suggestion 'c.get' var c = { get: function (key) { return 'foobar'; } }; c['hello']; -// Should give suggestion 'd.set' +var foo = c['hello']; var d = { set: function (key) { return 'foobar'; } }; -d['hello']; -// Should give suggestion 'e.get or e.set' +var bar = d['hello']; var e = { set: function (key) { return 'foobar'; }, get: function (key) { return 'foobar'; } }; -e['hello']; +e['hello'] = 'modified'; +e['hello'] += 1; +e['hello']++; diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols index 280f0784430a9..f86c0d14b6ff7 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.symbols @@ -7,43 +7,52 @@ var b: string = { '': 'foo' }['']; >'' : Symbol('', Decl(noImplicitAnyStringIndexerOnObject.ts, 1, 17)) >'' : Symbol('', Decl(noImplicitAnyStringIndexerOnObject.ts, 1, 17)) -// Should give suggestion 'c.get' var c = { ->c : Symbol(c, Decl(noImplicitAnyStringIndexerOnObject.ts, 4, 3)) +>c : Symbol(c, Decl(noImplicitAnyStringIndexerOnObject.ts, 3, 3)) get: (key: string) => 'foobar' ->get : Symbol(get, Decl(noImplicitAnyStringIndexerOnObject.ts, 4, 9)) ->key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 5, 8)) +>get : Symbol(get, Decl(noImplicitAnyStringIndexerOnObject.ts, 3, 9)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 4, 8)) }; c['hello']; ->c : Symbol(c, Decl(noImplicitAnyStringIndexerOnObject.ts, 4, 3)) +>c : Symbol(c, Decl(noImplicitAnyStringIndexerOnObject.ts, 3, 3)) + +const foo = c['hello']; +>foo : Symbol(foo, Decl(noImplicitAnyStringIndexerOnObject.ts, 7, 5)) +>c : Symbol(c, Decl(noImplicitAnyStringIndexerOnObject.ts, 3, 3)) -// Should give suggestion 'd.set' var d = { ->d : Symbol(d, Decl(noImplicitAnyStringIndexerOnObject.ts, 10, 3)) +>d : Symbol(d, Decl(noImplicitAnyStringIndexerOnObject.ts, 9, 3)) set: (key: string) => 'foobar' ->set : Symbol(set, Decl(noImplicitAnyStringIndexerOnObject.ts, 10, 9)) ->key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 11, 8)) +>set : Symbol(set, Decl(noImplicitAnyStringIndexerOnObject.ts, 9, 9)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 10, 8)) }; -d['hello']; ->d : Symbol(d, Decl(noImplicitAnyStringIndexerOnObject.ts, 10, 3)) +const bar = d['hello']; +>bar : Symbol(bar, Decl(noImplicitAnyStringIndexerOnObject.ts, 12, 5)) +>d : Symbol(d, Decl(noImplicitAnyStringIndexerOnObject.ts, 9, 3)) -// Should give suggestion 'e.get or e.set' var e = { ->e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 16, 3)) +>e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 14, 3)) set: (key: string) => 'foobar', ->set : Symbol(set, Decl(noImplicitAnyStringIndexerOnObject.ts, 16, 9)) ->key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 17, 8)) +>set : Symbol(set, Decl(noImplicitAnyStringIndexerOnObject.ts, 14, 9)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 15, 8)) get: (key: string) => 'foobar' ->get : Symbol(get, Decl(noImplicitAnyStringIndexerOnObject.ts, 17, 33)) ->key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 18, 8)) +>get : Symbol(get, Decl(noImplicitAnyStringIndexerOnObject.ts, 15, 33)) +>key : Symbol(key, Decl(noImplicitAnyStringIndexerOnObject.ts, 16, 8)) }; -e['hello']; ->e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 16, 3)) +e['hello'] = 'modified'; +>e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 14, 3)) + +e['hello'] += 1; +>e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 14, 3)) + +e['hello'] ++; +>e : Symbol(e, Decl(noImplicitAnyStringIndexerOnObject.ts, 14, 3)) + diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types index 20b517497d245..dcf01d8c5e8df 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types @@ -13,7 +13,6 @@ var b: string = { '': 'foo' }['']; >'foo' : "foo" >'' : "" -// Should give suggestion 'c.get' var c = { >c : { get: (key: string) => string; } >{ get: (key: string) => 'foobar'} : { get: (key: string) => string; } @@ -30,7 +29,12 @@ c['hello']; >c : { get: (key: string) => string; } >'hello' : "hello" -// Should give suggestion 'd.set' +const foo = c['hello']; +>foo : any +>c['hello'] : any +>c : { get: (key: string) => string; } +>'hello' : "hello" + var d = { >d : { set: (key: string) => string; } >{ set: (key: string) => 'foobar'} : { set: (key: string) => string; } @@ -42,12 +46,12 @@ var d = { >'foobar' : "foobar" }; -d['hello']; +const bar = d['hello']; +>bar : any >d['hello'] : any >d : { set: (key: string) => string; } >'hello' : "hello" -// Should give suggestion 'e.get or e.set' var e = { >e : { set: (key: string) => string; get: (key: string) => string; } >{ set: (key: string) => 'foobar', get: (key: string) => 'foobar'} : { set: (key: string) => string; get: (key: string) => string; } @@ -65,8 +69,24 @@ var e = { >'foobar' : "foobar" }; -e['hello']; +e['hello'] = 'modified'; +>e['hello'] = 'modified' : "modified" >e['hello'] : any >e : { set: (key: string) => string; get: (key: string) => string; } >'hello' : "hello" +>'modified' : "modified" + +e['hello'] += 1; +>e['hello'] += 1 : any +>e['hello'] : any +>e : { set: (key: string) => string; get: (key: string) => string; } +>'hello' : "hello" +>1 : 1 + +e['hello'] ++; +>e['hello'] ++ : number +>e['hello'] : any +>e : { set: (key: string) => string; get: (key: string) => string; } +>'hello' : "hello" + diff --git a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts index e627134bf6720..1cd967c294fb5 100644 --- a/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts +++ b/tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts @@ -7,14 +7,18 @@ var c = { get: (key: string) => 'foobar' }; c['hello']; +const foo = c['hello']; var d = { set: (key: string) => 'foobar' }; -d['hello']; +const bar = d['hello']; var e = { set: (key: string) => 'foobar', get: (key: string) => 'foobar' }; -e['hello']; +e['hello'] = 'modified'; +e['hello'] += 1; +e['hello'] ++; +