diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d9afe5e47eceb..79515bf075469 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13660,6 +13660,19 @@ namespace ts { return anyType; } if (accessExpression && !isConstEnumObjectType(objectType)) { + if (isObjectLiteralType(objectType)) { + if (noImplicitAny && indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { + diagnostics.add(createDiagnosticForNode(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType))); + return undefinedType; + } + else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { + const types = map((objectType).properties, property => { + return getTypeOfSymbol(property); + }); + return getUnionType(append(types, undefinedType)); + } + } + if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) { error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); } diff --git a/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.errors.txt b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.errors.txt new file mode 100644 index 0000000000000..3e9e1b0a1c11a --- /dev/null +++ b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.errors.txt @@ -0,0 +1,64 @@ +tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts(34,10): error TS2339: Property 'z' does not exist on type '{ a: number; b: string; c: boolean; }'. + + +==== tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts (1 errors) ==== + function foo (id: string) { + return { + a: 1, + b: "", + c: true + }[id] + } + + function bar (id: 'a' | 'b') { + return { + a: 1, + b: "", + c: false + }[id] + } + + function baz (id: '1' | '2') { + return { + 1: 1, + 2: "", + 3: false + }[id] + } + + function qux (id: 1 | 2) { + return { + 1: 1, + 2: "", + 3: false + }[id] + } + + function quux (id: 'a' | 'b' | 'z') { + return { + ~ + a: 1, + ~~~~~~~~~~~ + b: "", + ~~~~~~~~~~~~ + c: false + ~~~~~~~~~~~~~~ + }[id] + ~~~~~~~ +!!! error TS2339: Property 'z' does not exist on type '{ a: number; b: string; c: boolean; }'. + } + + function corge(id: string) { + return ({ + a: 123, + b: "" + } as Record)[id] + } + + function grault(id: string) { + return ({ + a: 123, + b: "" + } as { [k: string]: string | number})[id] + } + \ No newline at end of file diff --git a/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.js b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.js new file mode 100644 index 0000000000000..555eff83779b2 --- /dev/null +++ b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.js @@ -0,0 +1,105 @@ +//// [indexedAccessWithFreshObjectLiteral.ts] +function foo (id: string) { + return { + a: 1, + b: "", + c: true + }[id] +} + +function bar (id: 'a' | 'b') { + return { + a: 1, + b: "", + c: false + }[id] +} + +function baz (id: '1' | '2') { + return { + 1: 1, + 2: "", + 3: false + }[id] +} + +function qux (id: 1 | 2) { + return { + 1: 1, + 2: "", + 3: false + }[id] +} + +function quux (id: 'a' | 'b' | 'z') { + return { + a: 1, + b: "", + c: false + }[id] +} + +function corge(id: string) { + return ({ + a: 123, + b: "" + } as Record)[id] +} + +function grault(id: string) { + return ({ + a: 123, + b: "" + } as { [k: string]: string | number})[id] +} + + +//// [indexedAccessWithFreshObjectLiteral.js] +"use strict"; +function foo(id) { + return { + a: 1, + b: "", + c: true + }[id]; +} +function bar(id) { + return { + a: 1, + b: "", + c: false + }[id]; +} +function baz(id) { + return { + 1: 1, + 2: "", + 3: false + }[id]; +} +function qux(id) { + return { + 1: 1, + 2: "", + 3: false + }[id]; +} +function quux(id) { + return { + a: 1, + b: "", + c: false + }[id]; +} +function corge(id) { + return { + a: 123, + b: "" + }[id]; +} +function grault(id) { + return { + a: 123, + b: "" + }[id]; +} diff --git a/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.symbols b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.symbols new file mode 100644 index 0000000000000..d350699aaed58 --- /dev/null +++ b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.symbols @@ -0,0 +1,123 @@ +=== tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts === +function foo (id: string) { +>foo : Symbol(foo, Decl(indexedAccessWithFreshObjectLiteral.ts, 0, 0)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 0, 14)) + + return { + a: 1, +>a : Symbol(a, Decl(indexedAccessWithFreshObjectLiteral.ts, 1, 10)) + + b: "", +>b : Symbol(b, Decl(indexedAccessWithFreshObjectLiteral.ts, 2, 11)) + + c: true +>c : Symbol(c, Decl(indexedAccessWithFreshObjectLiteral.ts, 3, 12)) + + }[id] +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 0, 14)) +} + +function bar (id: 'a' | 'b') { +>bar : Symbol(bar, Decl(indexedAccessWithFreshObjectLiteral.ts, 6, 1)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 8, 14)) + + return { + a: 1, +>a : Symbol(a, Decl(indexedAccessWithFreshObjectLiteral.ts, 9, 10)) + + b: "", +>b : Symbol(b, Decl(indexedAccessWithFreshObjectLiteral.ts, 10, 11)) + + c: false +>c : Symbol(c, Decl(indexedAccessWithFreshObjectLiteral.ts, 11, 12)) + + }[id] +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 8, 14)) +} + +function baz (id: '1' | '2') { +>baz : Symbol(baz, Decl(indexedAccessWithFreshObjectLiteral.ts, 14, 1)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 16, 14)) + + return { + 1: 1, +>1 : Symbol(1, Decl(indexedAccessWithFreshObjectLiteral.ts, 17, 10)) + + 2: "", +>2 : Symbol(2, Decl(indexedAccessWithFreshObjectLiteral.ts, 18, 11)) + + 3: false +>3 : Symbol(3, Decl(indexedAccessWithFreshObjectLiteral.ts, 19, 12)) + + }[id] +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 16, 14)) +} + +function qux (id: 1 | 2) { +>qux : Symbol(qux, Decl(indexedAccessWithFreshObjectLiteral.ts, 22, 1)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 24, 14)) + + return { + 1: 1, +>1 : Symbol(1, Decl(indexedAccessWithFreshObjectLiteral.ts, 25, 10)) + + 2: "", +>2 : Symbol(2, Decl(indexedAccessWithFreshObjectLiteral.ts, 26, 11)) + + 3: false +>3 : Symbol(3, Decl(indexedAccessWithFreshObjectLiteral.ts, 27, 12)) + + }[id] +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 24, 14)) +} + +function quux (id: 'a' | 'b' | 'z') { +>quux : Symbol(quux, Decl(indexedAccessWithFreshObjectLiteral.ts, 30, 1)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 32, 15)) + + return { + a: 1, +>a : Symbol(a, Decl(indexedAccessWithFreshObjectLiteral.ts, 33, 10)) + + b: "", +>b : Symbol(b, Decl(indexedAccessWithFreshObjectLiteral.ts, 34, 11)) + + c: false +>c : Symbol(c, Decl(indexedAccessWithFreshObjectLiteral.ts, 35, 12)) + + }[id] +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 32, 15)) +} + +function corge(id: string) { +>corge : Symbol(corge, Decl(indexedAccessWithFreshObjectLiteral.ts, 38, 1)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 40, 15)) + + return ({ + a: 123, +>a : Symbol(a, Decl(indexedAccessWithFreshObjectLiteral.ts, 41, 11)) + + b: "" +>b : Symbol(b, Decl(indexedAccessWithFreshObjectLiteral.ts, 42, 13)) + + } as Record)[id] +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 40, 15)) +} + +function grault(id: string) { +>grault : Symbol(grault, Decl(indexedAccessWithFreshObjectLiteral.ts, 45, 1)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 47, 16)) + + return ({ + a: 123, +>a : Symbol(a, Decl(indexedAccessWithFreshObjectLiteral.ts, 48, 11)) + + b: "" +>b : Symbol(b, Decl(indexedAccessWithFreshObjectLiteral.ts, 49, 13)) + + } as { [k: string]: string | number})[id] +>k : Symbol(k, Decl(indexedAccessWithFreshObjectLiteral.ts, 51, 10)) +>id : Symbol(id, Decl(indexedAccessWithFreshObjectLiteral.ts, 47, 16)) +} + diff --git a/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.types b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.types new file mode 100644 index 0000000000000..3af90c3f15bdb --- /dev/null +++ b/tests/baselines/reference/indexedAccessWithFreshObjectLiteral.types @@ -0,0 +1,166 @@ +=== tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts === +function foo (id: string) { +>foo : (id: string) => string | number | boolean | undefined +>id : string + + return { +>{ a: 1, b: "", c: true }[id] : string | number | boolean | undefined +>{ a: 1, b: "", c: true } : { a: number; b: string; c: boolean; } + + a: 1, +>a : number +>1 : 1 + + b: "", +>b : string +>"" : "" + + c: true +>c : boolean +>true : true + + }[id] +>id : string +} + +function bar (id: 'a' | 'b') { +>bar : (id: 'a' | 'b') => string | number +>id : "a" | "b" + + return { +>{ a: 1, b: "", c: false }[id] : string | number +>{ a: 1, b: "", c: false } : { a: number; b: string; c: boolean; } + + a: 1, +>a : number +>1 : 1 + + b: "", +>b : string +>"" : "" + + c: false +>c : boolean +>false : false + + }[id] +>id : "a" | "b" +} + +function baz (id: '1' | '2') { +>baz : (id: '1' | '2') => string | number +>id : "1" | "2" + + return { +>{ 1: 1, 2: "", 3: false }[id] : string | number +>{ 1: 1, 2: "", 3: false } : { 1: number; 2: string; 3: boolean; } + + 1: 1, +>1 : number +>1 : 1 + + 2: "", +>2 : string +>"" : "" + + 3: false +>3 : boolean +>false : false + + }[id] +>id : "1" | "2" +} + +function qux (id: 1 | 2) { +>qux : (id: 1 | 2) => string | number +>id : 1 | 2 + + return { +>{ 1: 1, 2: "", 3: false }[id] : string | number +>{ 1: 1, 2: "", 3: false } : { 1: number; 2: string; 3: boolean; } + + 1: 1, +>1 : number +>1 : 1 + + 2: "", +>2 : string +>"" : "" + + 3: false +>3 : boolean +>false : false + + }[id] +>id : 1 | 2 +} + +function quux (id: 'a' | 'b' | 'z') { +>quux : (id: 'a' | 'b' | 'z') => string | number | undefined +>id : "a" | "b" | "z" + + return { +>{ a: 1, b: "", c: false }[id] : string | number | undefined +>{ a: 1, b: "", c: false } : { a: number; b: string; c: boolean; } + + a: 1, +>a : number +>1 : 1 + + b: "", +>b : string +>"" : "" + + c: false +>c : boolean +>false : false + + }[id] +>id : "a" | "b" | "z" +} + +function corge(id: string) { +>corge : (id: string) => string | number +>id : string + + return ({ +>({ a: 123, b: "" } as Record)[id] : string | number +>({ a: 123, b: "" } as Record) : Record +>{ a: 123, b: "" } as Record : Record +>{ a: 123, b: "" } : { a: number; b: string; } + + a: 123, +>a : number +>123 : 123 + + b: "" +>b : string +>"" : "" + + } as Record)[id] +>id : string +} + +function grault(id: string) { +>grault : (id: string) => string | number +>id : string + + return ({ +>({ a: 123, b: "" } as { [k: string]: string | number})[id] : string | number +>({ a: 123, b: "" } as { [k: string]: string | number}) : { [k: string]: string | number; } +>{ a: 123, b: "" } as { [k: string]: string | number} : { [k: string]: string | number; } +>{ a: 123, b: "" } : { a: number; b: string; } + + a: 123, +>a : number +>123 : 123 + + b: "" +>b : string +>"" : "" + + } as { [k: string]: string | number})[id] +>k : string +>id : string +} + diff --git a/tests/baselines/reference/noImplicitAnyIndexing.errors.txt b/tests/baselines/reference/noImplicitAnyIndexing.errors.txt index f9631f29aa1f1..20852f9cc333a 100644 --- a/tests/baselines/reference/noImplicitAnyIndexing.errors.txt +++ b/tests/baselines/reference/noImplicitAnyIndexing.errors.txt @@ -1,8 +1,6 @@ tests/cases/compiler/noImplicitAnyIndexing.ts(12,37): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. -tests/cases/compiler/noImplicitAnyIndexing.ts(19,9): error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type '{}'. - Property 'hi' does not exist on type '{}'. -tests/cases/compiler/noImplicitAnyIndexing.ts(22,9): error TS7053: Element implicitly has an 'any' type because expression of type '10' can't be used to index type '{}'. - Property '10' does not exist on type '{}'. +tests/cases/compiler/noImplicitAnyIndexing.ts(19,9): error TS2339: Property 'hi' does not exist on type '{}'. +tests/cases/compiler/noImplicitAnyIndexing.ts(22,9): error TS2339: Property '10' does not exist on type '{}'. tests/cases/compiler/noImplicitAnyIndexing.ts(30,10): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}'. @@ -29,14 +27,12 @@ tests/cases/compiler/noImplicitAnyIndexing.ts(30,10): error TS7053: Element impl // Should report an implicit 'any'. var x = {}["hi"]; ~~~~~~~~ -!!! error TS7053: Element implicitly has an 'any' type because expression of type '"hi"' can't be used to index type '{}'. -!!! error TS7053: Property 'hi' does not exist on type '{}'. +!!! error TS2339: Property 'hi' does not exist on type '{}'. // Should report an implicit 'any'. var y = {}[10]; ~~~~~~ -!!! error TS7053: Element implicitly has an 'any' type because expression of type '10' can't be used to index type '{}'. -!!! error TS7053: Property '10' does not exist on type '{}'. +!!! error TS2339: Property '10' does not exist on type '{}'. var hi: any = "hi"; diff --git a/tests/baselines/reference/noImplicitAnyIndexing.types b/tests/baselines/reference/noImplicitAnyIndexing.types index 2bd27cb0c0b47..165e9f64e3dca 100644 --- a/tests/baselines/reference/noImplicitAnyIndexing.types +++ b/tests/baselines/reference/noImplicitAnyIndexing.types @@ -39,15 +39,15 @@ var strRepresentation4 = MyEmusEnum["emu"]; // Should report an implicit 'any'. var x = {}["hi"]; ->x : any ->{}["hi"] : any +>x : undefined +>{}["hi"] : undefined >{} : {} >"hi" : "hi" // Should report an implicit 'any'. var y = {}[10]; ->y : any ->{}[10] : any +>y : undefined +>{}[10] : undefined >{} : {} >10 : 10 diff --git a/tests/baselines/reference/noImplicitAnyIndexingSuppressed.errors.txt b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.errors.txt new file mode 100644 index 0000000000000..e6e668fa0915f --- /dev/null +++ b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.errors.txt @@ -0,0 +1,56 @@ +tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts(19,9): error TS2339: Property 'hi' does not exist on type '{}'. +tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts(22,9): error TS2339: Property '10' does not exist on type '{}'. + + +==== tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts (2 errors) ==== + enum MyEmusEnum { + emu + } + + // Should be okay; should be a string. + var strRepresentation1 = MyEmusEnum[0] + + // Should be okay; should be a string. + var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu] + + // Should be okay, as we suppress implicit 'any' property access checks + var strRepresentation3 = MyEmusEnum["monehh"]; + + // Should be okay; should be a MyEmusEnum + var strRepresentation4 = MyEmusEnum["emu"]; + + + // Should be okay, as we suppress implicit 'any' property access checks + var x = {}["hi"]; + ~~~~~~~~ +!!! error TS2339: Property 'hi' does not exist on type '{}'. + + // Should be okay, as we suppress implicit 'any' property access checks + var y = {}[10]; + ~~~~~~ +!!! error TS2339: Property '10' does not exist on type '{}'. + + var hi: any = "hi"; + + var emptyObj = {}; + + // Should be okay, as we suppress implicit 'any' property access checks + var z1 = emptyObj[hi]; + var z2 = (emptyObj)[hi]; + + interface MyMap { + [key: string]: T; + } + + var m: MyMap = { + "0": 0, + "1": 1, + "2": 2, + "Okay that's enough for today.": NaN + }; + + var mResult1 = m[MyEmusEnum.emu]; + var mResult2 = m[MyEmusEnum[MyEmusEnum.emu]]; + var mResult3 = m[hi]; + + \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitAnyIndexingSuppressed.types b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.types index fe10152e90c70..91b95cb9f4bf2 100644 --- a/tests/baselines/reference/noImplicitAnyIndexingSuppressed.types +++ b/tests/baselines/reference/noImplicitAnyIndexingSuppressed.types @@ -24,8 +24,8 @@ var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu] // Should be okay, as we suppress implicit 'any' property access checks var strRepresentation3 = MyEmusEnum["monehh"]; ->strRepresentation3 : error ->MyEmusEnum["monehh"] : error +>strRepresentation3 : any +>MyEmusEnum["monehh"] : any >MyEmusEnum : typeof MyEmusEnum >"monehh" : "monehh" @@ -39,15 +39,15 @@ var strRepresentation4 = MyEmusEnum["emu"]; // Should be okay, as we suppress implicit 'any' property access checks var x = {}["hi"]; ->x : error ->{}["hi"] : error +>x : undefined +>{}["hi"] : undefined >{} : {} >"hi" : "hi" // Should be okay, as we suppress implicit 'any' property access checks var y = {}[10]; ->y : error ->{}[10] : error +>y : undefined +>{}[10] : undefined >{} : {} >10 : 10 @@ -61,8 +61,8 @@ var emptyObj = {}; // Should be okay, as we suppress implicit 'any' property access checks var z1 = emptyObj[hi]; ->z1 : error ->emptyObj[hi] : error +>z1 : any +>emptyObj[hi] : any >emptyObj : {} >hi : any diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt index 9e547245d9475..5c1daf0fc5709 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt @@ -1,5 +1,4 @@ -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(1,9): error TS7053: Element implicitly has an 'any' type because expression of type '"hello"' can't be used to index type '{}'. - Property 'hello' does not exist on type '{}'. +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(1,9): error TS2339: Property 'hello' does not exist on type '{}'. 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 'c.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 'c.get'? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(13,13): error TS7053: Element implicitly has an 'any' type because expression of type '"hello"' can't be used to index type '{ set: (key: string) => string; }'. @@ -16,11 +15,11 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(42,3): error TS7052: tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(43,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: "hello" | "world") => string; set: (key: "hello" | "world", value: string) => string; }' has no index signature. Did you mean to call 'e.set'? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(44,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: "hello" | "world") => string; set: (key: "hello" | "world", value: string) => string; }' has no index signature. Did you mean to call 'e.set'? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(45,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: "hello" | "world") => string; set: (key: "hello" | "world", value: string) => string; }' has no index signature. Did you mean to call 'e.set'? -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(49,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'get'? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(49,3): error TS2339: Property 'hello' does not exist on type '{ get: (key: string) => string; set: (key: string, value: string) => void; }'. tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(50,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(51,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(52,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? -tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(56,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'get'? +tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(56,3): error TS2339: Property 'hello' does not exist on type '{ get: (key: string) => string; set: (key: string, value: string) => void; }'. tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(57,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(58,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(59,3): error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? @@ -41,8 +40,7 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(99,1): error TS7052: ==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (31 errors) ==== var a = {}["hello"]; ~~~~~~~~~~~ -!!! error TS7053: Element implicitly has an 'any' type because expression of type '"hello"' can't be used to index type '{}'. -!!! error TS7053: Property 'hello' does not exist on type '{}'. +!!! error TS2339: Property 'hello' does not exist on type '{}'. var b: string = { '': 'foo' }['']; var c = { @@ -123,7 +121,7 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(99,1): error TS7052: { ({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello']; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'get'? +!!! error TS2339: Property 'hello' does not exist on type '{ get: (key: string) => string; set: (key: string, value: string) => void; }'. ({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'] = 'modified'; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? @@ -138,7 +136,7 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(99,1): error TS7052: { ({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello']; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'get'? +!!! error TS2339: Property 'hello' does not exist on type '{ get: (key: string) => string; set: (key: string, value: string) => void; }'. ({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'] = 'modified'; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS7052: Element implicitly has an 'any' type because type '{ get: (key: string) => string; set: (key: string, value: string) => void; }' has no index signature. Did you mean to call 'set'? diff --git a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types index 20aa05cb40e8a..b50b387586816 100644 --- a/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types +++ b/tests/baselines/reference/noImplicitAnyStringIndexerOnObject.types @@ -1,7 +1,7 @@ === tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts === var a = {}["hello"]; ->a : any ->{}["hello"] : any +>a : undefined +>{}["hello"] : undefined >{} : {} >"hello" : "hello" @@ -188,7 +188,7 @@ const bar = d['hello']; { ({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello']; ->({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'] : any +>({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'] : undefined >({ get: (key: string) => 'hello', set: (key: string, value: string) => {} }) : { get: (key: string) => string; set: (key: string, value: string) => void; } >{ get: (key: string) => 'hello', set: (key: string, value: string) => {} } : { get: (key: string) => string; set: (key: string, value: string) => void; } >get : (key: string) => string @@ -251,7 +251,7 @@ const bar = d['hello']; { ({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello']; ->({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'] : any +>({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'] : undefined >({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo : { get: (key: string) => string; set: (key: string, value: string) => void; } >({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }) : { foo: { get: (key: string) => string; set: (key: string, value: string) => void; }; } >{ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } } : { foo: { get: (key: string) => string; set: (key: string, value: string) => void; }; } diff --git a/tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts b/tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts new file mode 100644 index 0000000000000..d64bdb6550652 --- /dev/null +++ b/tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts @@ -0,0 +1,55 @@ +// @strict: true + +function foo (id: string) { + return { + a: 1, + b: "", + c: true + }[id] +} + +function bar (id: 'a' | 'b') { + return { + a: 1, + b: "", + c: false + }[id] +} + +function baz (id: '1' | '2') { + return { + 1: 1, + 2: "", + 3: false + }[id] +} + +function qux (id: 1 | 2) { + return { + 1: 1, + 2: "", + 3: false + }[id] +} + +function quux (id: 'a' | 'b' | 'z') { + return { + a: 1, + b: "", + c: false + }[id] +} + +function corge(id: string) { + return ({ + a: 123, + b: "" + } as Record)[id] +} + +function grault(id: string) { + return ({ + a: 123, + b: "" + } as { [k: string]: string | number})[id] +}