Skip to content

Commit 2ce92c4

Browse files
committed
Update the logic in getPropertyTypeForIndexType
1 parent c38c41a commit 2ce92c4

8 files changed

+142
-155
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12701,6 +12701,19 @@ namespace ts {
1270112701
return anyType;
1270212702
}
1270312703
if (accessExpression && !isConstEnumObjectType(objectType)) {
12704+
if (isObjectLiteralType(objectType)) {
12705+
if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
12706+
return undefinedType;
12707+
}
12708+
else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) {
12709+
const types = (<ResolvedType>objectType).properties
12710+
.map(property => {
12711+
return getTypeOfSymbol(property);
12712+
});
12713+
return getUnionType(append(types, undefinedType));
12714+
}
12715+
}
12716+
1270412717
if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) {
1270512718
error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType));
1270612719
}
@@ -24435,26 +24448,6 @@ namespace ts {
2443524448
}
2443624449

2443724450
const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType;
24438-
const expression = walkUpParenthesizedExpressions(node.expression);
24439-
if (isObjectLiteralExpression(expression) && isTypeAssignableToKind(effectiveIndexType, TypeFlags.StringLike | TypeFlags.NumberLike) && !getIndexInfoOfType(objectType, IndexKind.Number | IndexKind.String)) {
24440-
const members = (<ResolvedType>objectType).members;
24441-
const matchedIndex = filterType(effectiveIndexType, type => {
24442-
const value = String((<LiteralType>type).value);
24443-
return !!(type.flags & TypeFlags.StringOrNumberLiteral && members.has(value as __String));
24444-
});
24445-
24446-
if (matchedIndex === neverType) {
24447-
return getUnionType(append(arrayFrom(members.values(), getTypeOfSymbol), undefinedType));
24448-
}
24449-
24450-
const allMatch = matchedIndex === effectiveIndexType;
24451-
const u = allMatch ? undefined : undefinedType;
24452-
return getUnionType(append([mapType(matchedIndex, type => {
24453-
const value = String((<LiteralType>type).value);
24454-
return getTypeOfSymbol(members.get(value as __String)!);
24455-
})], u));
24456-
}
24457-
2445824451
const accessFlags = isAssignmentTarget(node) ?
2445924452
AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) :
2446024453
AccessFlags.None;

tests/baselines/reference/indexedAccessWithFreshObjectLiteral.symbols

Lines changed: 0 additions & 123 deletions
This file was deleted.

tests/baselines/reference/indexedAccessWithFreshObjectLiteral.js renamed to tests/baselines/reference/indexedAccessWithObjectLiteral.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//// [indexedAccessWithFreshObjectLiteral.ts]
1+
//// [indexedAccessWithObjectLiteral.ts]
22
function foo (id: string) {
33
return {
44
a: 1,
@@ -54,7 +54,7 @@ function grault(id: string) {
5454
}
5555

5656

57-
//// [indexedAccessWithFreshObjectLiteral.js]
57+
//// [indexedAccessWithObjectLiteral.js]
5858
"use strict";
5959
function foo(id) {
6060
return {
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
=== tests/cases/compiler/indexedAccessWithObjectLiteral.ts ===
2+
function foo (id: string) {
3+
>foo : Symbol(foo, Decl(indexedAccessWithObjectLiteral.ts, 0, 0))
4+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 0, 14))
5+
6+
return {
7+
a: 1,
8+
>a : Symbol(a, Decl(indexedAccessWithObjectLiteral.ts, 1, 10))
9+
10+
b: "",
11+
>b : Symbol(b, Decl(indexedAccessWithObjectLiteral.ts, 2, 11))
12+
13+
c: true
14+
>c : Symbol(c, Decl(indexedAccessWithObjectLiteral.ts, 3, 12))
15+
16+
}[id]
17+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 0, 14))
18+
}
19+
20+
function bar (id: 'a' | 'b') {
21+
>bar : Symbol(bar, Decl(indexedAccessWithObjectLiteral.ts, 6, 1))
22+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 8, 14))
23+
24+
return {
25+
a: 1,
26+
>a : Symbol(a, Decl(indexedAccessWithObjectLiteral.ts, 9, 10))
27+
28+
b: "",
29+
>b : Symbol(b, Decl(indexedAccessWithObjectLiteral.ts, 10, 11))
30+
31+
c: false
32+
>c : Symbol(c, Decl(indexedAccessWithObjectLiteral.ts, 11, 12))
33+
34+
}[id]
35+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 8, 14))
36+
}
37+
38+
function baz (id: '1' | '2') {
39+
>baz : Symbol(baz, Decl(indexedAccessWithObjectLiteral.ts, 14, 1))
40+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 16, 14))
41+
42+
return {
43+
1: 1,
44+
>1 : Symbol(1, Decl(indexedAccessWithObjectLiteral.ts, 17, 10))
45+
46+
2: "",
47+
>2 : Symbol(2, Decl(indexedAccessWithObjectLiteral.ts, 18, 11))
48+
49+
3: false
50+
>3 : Symbol(3, Decl(indexedAccessWithObjectLiteral.ts, 19, 12))
51+
52+
}[id]
53+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 16, 14))
54+
}
55+
56+
function qux (id: 1 | 2) {
57+
>qux : Symbol(qux, Decl(indexedAccessWithObjectLiteral.ts, 22, 1))
58+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 24, 14))
59+
60+
return {
61+
1: 1,
62+
>1 : Symbol(1, Decl(indexedAccessWithObjectLiteral.ts, 25, 10))
63+
64+
2: "",
65+
>2 : Symbol(2, Decl(indexedAccessWithObjectLiteral.ts, 26, 11))
66+
67+
3: false
68+
>3 : Symbol(3, Decl(indexedAccessWithObjectLiteral.ts, 27, 12))
69+
70+
}[id]
71+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 24, 14))
72+
}
73+
74+
function quux (id: 'a' | 'b' | 'z') {
75+
>quux : Symbol(quux, Decl(indexedAccessWithObjectLiteral.ts, 30, 1))
76+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 32, 15))
77+
78+
return {
79+
a: 1,
80+
>a : Symbol(a, Decl(indexedAccessWithObjectLiteral.ts, 33, 10))
81+
82+
b: "",
83+
>b : Symbol(b, Decl(indexedAccessWithObjectLiteral.ts, 34, 11))
84+
85+
c: false
86+
>c : Symbol(c, Decl(indexedAccessWithObjectLiteral.ts, 35, 12))
87+
88+
}[id]
89+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 32, 15))
90+
}
91+
92+
function corge(id: string) {
93+
>corge : Symbol(corge, Decl(indexedAccessWithObjectLiteral.ts, 38, 1))
94+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 40, 15))
95+
96+
return ({
97+
a: 123,
98+
>a : Symbol(a, Decl(indexedAccessWithObjectLiteral.ts, 41, 11))
99+
100+
b: ""
101+
>b : Symbol(b, Decl(indexedAccessWithObjectLiteral.ts, 42, 13))
102+
103+
} as Record<string, number | string>)[id]
104+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
105+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 40, 15))
106+
}
107+
108+
function grault(id: string) {
109+
>grault : Symbol(grault, Decl(indexedAccessWithObjectLiteral.ts, 45, 1))
110+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 47, 16))
111+
112+
return ({
113+
a: 123,
114+
>a : Symbol(a, Decl(indexedAccessWithObjectLiteral.ts, 48, 11))
115+
116+
b: ""
117+
>b : Symbol(b, Decl(indexedAccessWithObjectLiteral.ts, 49, 13))
118+
119+
} as { [k: string]: string | number})[id]
120+
>k : Symbol(k, Decl(indexedAccessWithObjectLiteral.ts, 51, 10))
121+
>id : Symbol(id, Decl(indexedAccessWithObjectLiteral.ts, 47, 16))
122+
}
123+

tests/baselines/reference/indexedAccessWithFreshObjectLiteral.types renamed to tests/baselines/reference/indexedAccessWithObjectLiteral.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
=== tests/cases/compiler/indexedAccessWithFreshObjectLiteral.ts ===
1+
=== tests/cases/compiler/indexedAccessWithObjectLiteral.ts ===
22
function foo (id: string) {
33
>foo : (id: string) => string | number | boolean | undefined
44
>id : string

tests/baselines/reference/noImplicitAnyStringIndexerOnObject.errors.txt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(42,3): error TS7052:
1414
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'?
1515
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'?
1616
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'?
17-
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'?
1817
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'?
1918
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'?
2019
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'?
21-
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'?
2220
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'?
2321
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'?
2422
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'?
@@ -35,7 +33,7 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(81,1): error TS7053:
3533
tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(93,5): error TS2538: Type 'Dog' cannot be used as an index type.
3634

3735

38-
==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (29 errors) ====
36+
==== tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts (27 errors) ====
3937
var a = {}["hello"];
4038
var b: string = { '': 'foo' }[''];
4139

@@ -116,8 +114,6 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(93,5): error TS2538:
116114

117115
{
118116
({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'];
119-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
120-
!!! 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'?
121117
({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'] = 'modified';
122118
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123119
!!! 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'?
@@ -131,8 +127,6 @@ tests/cases/compiler/noImplicitAnyStringIndexerOnObject.ts(93,5): error TS2538:
131127

132128
{
133129
({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'];
134-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135-
!!! 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'?
136130
({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'] = 'modified';
137131
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
138132
!!! 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/baselines/reference/noImplicitAnyStringIndexerOnObject.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ const bar = d['hello'];
188188

189189
{
190190
({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'];
191-
>({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'] : any
191+
>({ get: (key: string) => 'hello', set: (key: string, value: string) => {} })['hello'] : undefined
192192
>({ get: (key: string) => 'hello', set: (key: string, value: string) => {} }) : { get: (key: string) => string; set: (key: string, value: string) => void; }
193193
>{ get: (key: string) => 'hello', set: (key: string, value: string) => {} } : { get: (key: string) => string; set: (key: string, value: string) => void; }
194194
>get : (key: string) => string
@@ -251,7 +251,7 @@ const bar = d['hello'];
251251

252252
{
253253
({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'];
254-
>({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'] : any
254+
>({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo['hello'] : undefined
255255
>({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }).foo : { get: (key: string) => string; set: (key: string, value: string) => void; }
256256
>({ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } }) : { foo: { get: (key: string) => string; set: (key: string, value: string) => void; }; }
257257
>{ foo: { get: (key: string) => 'hello', set: (key: string, value: string) => {} } } : { foo: { get: (key: string) => string; set: (key: string, value: string) => void; }; }

0 commit comments

Comments
 (0)