Skip to content

Commit b3161e3

Browse files
authored
Merge pull request microsoft#14222 from Microsoft/addAnyStringIndexerToJSObjects
Add a string indexer to any for object literals on a .js file
2 parents 0425175 + 7e2abfc commit b3161e3

File tree

7 files changed

+313
-8
lines changed

7 files changed

+313
-8
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ namespace ts {
244244
const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
245245

246246
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
247+
const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
247248

248249
const globals = createMap<Symbol>();
249250
/**
@@ -12252,6 +12253,7 @@ namespace ts {
1225212253
const contextualType = getApparentTypeOfContextualType(node);
1225312254
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
1225412255
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
12256+
const isJSObjectLiteral = !contextualType && isInJavaScriptFile(node);
1225512257
let typeFlags: TypeFlags = 0;
1225612258
let patternWithComputedProperties = false;
1225712259
let hasComputedStringProperty = false;
@@ -12389,8 +12391,8 @@ namespace ts {
1238912391
return createObjectLiteralType();
1239012392

1239112393
function createObjectLiteralType() {
12392-
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
12393-
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
12394+
const stringIndexInfo = isJSObjectLiteral ? jsObjectLiteralIndexInfo : hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
12395+
const numberIndexInfo = hasComputedNumberProperty && !isJSObjectLiteral ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
1239412396
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
1239512397
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
1239612398
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);

tests/baselines/reference/jsFileCompilationShortHandProperty.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
=== tests/cases/compiler/a.js ===
22

33
function foo() {
4-
>foo : () => { a: number; b: string; }
4+
>foo : () => { [x: string]: any; a: number; b: string; }
55

66
var a = 10;
77
>a : number
@@ -12,7 +12,7 @@ function foo() {
1212
>"Hello" : "Hello"
1313

1414
return {
15-
>{ a, b } : { a: number; b: string; }
15+
>{ a, b } : { [x: string]: any; a: number; b: string; }
1616

1717
a,
1818
>a : number
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//// [tests/cases/conformance/salsa/jsObjectsMarkedAsOpenEnded.ts] ////
2+
3+
//// [a.js]
4+
5+
var variable = {};
6+
variable.a = 0;
7+
8+
class C {
9+
initializedMember = {};
10+
constructor() {
11+
this.member = {};
12+
this.member.a = 0;
13+
}
14+
}
15+
16+
var obj = {
17+
property: {}
18+
};
19+
20+
obj.property.a = 0;
21+
22+
var arr = [{}];
23+
24+
function getObj() {
25+
return {};
26+
}
27+
28+
29+
//// [b.ts]
30+
variable.a = 1;
31+
(new C()).member.a = 1;
32+
(new C()).initializedMember.a = 1;
33+
obj.property.a = 1;
34+
arr[0].a = 1;
35+
getObj().a = 1;
36+
37+
38+
39+
//// [output.js]
40+
var variable = {};
41+
variable.a = 0;
42+
var C = (function () {
43+
function C() {
44+
this.initializedMember = {};
45+
this.member = {};
46+
this.member.a = 0;
47+
}
48+
return C;
49+
}());
50+
var obj = {
51+
property: {}
52+
};
53+
obj.property.a = 0;
54+
var arr = [{}];
55+
function getObj() {
56+
return {};
57+
}
58+
variable.a = 1;
59+
(new C()).member.a = 1;
60+
(new C()).initializedMember.a = 1;
61+
obj.property.a = 1;
62+
arr[0].a = 1;
63+
getObj().a = 1;
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
=== tests/cases/conformance/salsa/a.js ===
2+
3+
var variable = {};
4+
>variable : Symbol(variable, Decl(a.js, 1, 3))
5+
6+
variable.a = 0;
7+
>variable : Symbol(variable, Decl(a.js, 1, 3))
8+
9+
class C {
10+
>C : Symbol(C, Decl(a.js, 2, 15))
11+
12+
initializedMember = {};
13+
>initializedMember : Symbol(C.initializedMember, Decl(a.js, 4, 9))
14+
15+
constructor() {
16+
this.member = {};
17+
>this.member : Symbol(C.member, Decl(a.js, 6, 19))
18+
>this : Symbol(C, Decl(a.js, 2, 15))
19+
>member : Symbol(C.member, Decl(a.js, 6, 19))
20+
21+
this.member.a = 0;
22+
>this.member : Symbol(C.member, Decl(a.js, 6, 19))
23+
>this : Symbol(C, Decl(a.js, 2, 15))
24+
>member : Symbol(C.member, Decl(a.js, 6, 19))
25+
}
26+
}
27+
28+
var obj = {
29+
>obj : Symbol(obj, Decl(a.js, 12, 3))
30+
31+
property: {}
32+
>property : Symbol(property, Decl(a.js, 12, 11))
33+
34+
};
35+
36+
obj.property.a = 0;
37+
>obj.property : Symbol(property, Decl(a.js, 12, 11))
38+
>obj : Symbol(obj, Decl(a.js, 12, 3))
39+
>property : Symbol(property, Decl(a.js, 12, 11))
40+
41+
var arr = [{}];
42+
>arr : Symbol(arr, Decl(a.js, 18, 3))
43+
44+
function getObj() {
45+
>getObj : Symbol(getObj, Decl(a.js, 18, 15))
46+
47+
return {};
48+
}
49+
50+
51+
=== tests/cases/conformance/salsa/b.ts ===
52+
variable.a = 1;
53+
>variable : Symbol(variable, Decl(a.js, 1, 3))
54+
55+
(new C()).member.a = 1;
56+
>(new C()).member : Symbol(C.member, Decl(a.js, 6, 19))
57+
>C : Symbol(C, Decl(a.js, 2, 15))
58+
>member : Symbol(C.member, Decl(a.js, 6, 19))
59+
60+
(new C()).initializedMember.a = 1;
61+
>(new C()).initializedMember : Symbol(C.initializedMember, Decl(a.js, 4, 9))
62+
>C : Symbol(C, Decl(a.js, 2, 15))
63+
>initializedMember : Symbol(C.initializedMember, Decl(a.js, 4, 9))
64+
65+
obj.property.a = 1;
66+
>obj.property : Symbol(property, Decl(a.js, 12, 11))
67+
>obj : Symbol(obj, Decl(a.js, 12, 3))
68+
>property : Symbol(property, Decl(a.js, 12, 11))
69+
70+
arr[0].a = 1;
71+
>arr : Symbol(arr, Decl(a.js, 18, 3))
72+
73+
getObj().a = 1;
74+
>getObj : Symbol(getObj, Decl(a.js, 18, 15))
75+
76+
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
=== tests/cases/conformance/salsa/a.js ===
2+
3+
var variable = {};
4+
>variable : { [x: string]: any; }
5+
>{} : { [x: string]: any; }
6+
7+
variable.a = 0;
8+
>variable.a = 0 : 0
9+
>variable.a : any
10+
>variable : { [x: string]: any; }
11+
>a : any
12+
>0 : 0
13+
14+
class C {
15+
>C : C
16+
17+
initializedMember = {};
18+
>initializedMember : { [x: string]: any; }
19+
>{} : { [x: string]: any; }
20+
21+
constructor() {
22+
this.member = {};
23+
>this.member = {} : { [x: string]: any; }
24+
>this.member : { [x: string]: any; }
25+
>this : this
26+
>member : { [x: string]: any; }
27+
>{} : { [x: string]: any; }
28+
29+
this.member.a = 0;
30+
>this.member.a = 0 : 0
31+
>this.member.a : any
32+
>this.member : { [x: string]: any; }
33+
>this : this
34+
>member : { [x: string]: any; }
35+
>a : any
36+
>0 : 0
37+
}
38+
}
39+
40+
var obj = {
41+
>obj : { [x: string]: any; property: { [x: string]: any; }; }
42+
>{ property: {}} : { [x: string]: any; property: { [x: string]: any; }; }
43+
44+
property: {}
45+
>property : { [x: string]: any; }
46+
>{} : { [x: string]: any; }
47+
48+
};
49+
50+
obj.property.a = 0;
51+
>obj.property.a = 0 : 0
52+
>obj.property.a : any
53+
>obj.property : { [x: string]: any; }
54+
>obj : { [x: string]: any; property: { [x: string]: any; }; }
55+
>property : { [x: string]: any; }
56+
>a : any
57+
>0 : 0
58+
59+
var arr = [{}];
60+
>arr : { [x: string]: any; }[]
61+
>[{}] : { [x: string]: any; }[]
62+
>{} : { [x: string]: any; }
63+
64+
function getObj() {
65+
>getObj : () => { [x: string]: any; }
66+
67+
return {};
68+
>{} : { [x: string]: any; }
69+
}
70+
71+
72+
=== tests/cases/conformance/salsa/b.ts ===
73+
variable.a = 1;
74+
>variable.a = 1 : 1
75+
>variable.a : any
76+
>variable : { [x: string]: any; }
77+
>a : any
78+
>1 : 1
79+
80+
(new C()).member.a = 1;
81+
>(new C()).member.a = 1 : 1
82+
>(new C()).member.a : any
83+
>(new C()).member : { [x: string]: any; }
84+
>(new C()) : C
85+
>new C() : C
86+
>C : typeof C
87+
>member : { [x: string]: any; }
88+
>a : any
89+
>1 : 1
90+
91+
(new C()).initializedMember.a = 1;
92+
>(new C()).initializedMember.a = 1 : 1
93+
>(new C()).initializedMember.a : any
94+
>(new C()).initializedMember : { [x: string]: any; }
95+
>(new C()) : C
96+
>new C() : C
97+
>C : typeof C
98+
>initializedMember : { [x: string]: any; }
99+
>a : any
100+
>1 : 1
101+
102+
obj.property.a = 1;
103+
>obj.property.a = 1 : 1
104+
>obj.property.a : any
105+
>obj.property : { [x: string]: any; }
106+
>obj : { [x: string]: any; property: { [x: string]: any; }; }
107+
>property : { [x: string]: any; }
108+
>a : any
109+
>1 : 1
110+
111+
arr[0].a = 1;
112+
>arr[0].a = 1 : 1
113+
>arr[0].a : any
114+
>arr[0] : { [x: string]: any; }
115+
>arr : { [x: string]: any; }[]
116+
>0 : 0
117+
>a : any
118+
>1 : 1
119+
120+
getObj().a = 1;
121+
>getObj().a = 1 : 1
122+
>getObj().a : any
123+
>getObj() : { [x: string]: any; }
124+
>getObj : () => { [x: string]: any; }
125+
>a : any
126+
>1 : 1
127+
128+
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
=== /a.ts ===
22
import foo from "foo";
3-
>foo : { bar(): number; }
3+
>foo : { [x: string]: any; bar(): number; }
44

55
foo.bar();
66
>foo.bar() : number
77
>foo.bar : () => number
8-
>foo : { bar(): number; }
8+
>foo : { [x: string]: any; bar(): number; }
99
>bar : () => number
1010

1111
=== /node_modules/foo/index.js ===
1212
// Same as untypedModuleImport.ts but with --allowJs, so the package will actually be typed.
1313

1414
exports.default = { bar() { return 0; } }
15-
>exports.default = { bar() { return 0; } } : { bar(): number; }
15+
>exports.default = { bar() { return 0; } } : { [x: string]: any; bar(): number; }
1616
>exports.default : any
1717
>exports : any
1818
>default : any
19-
>{ bar() { return 0; } } : { bar(): number; }
19+
>{ bar() { return 0; } } : { [x: string]: any; bar(): number; }
2020
>bar : () => number
2121
>0 : 0
2222

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// @out: output.js
2+
// @allowJs: true
3+
4+
// @filename: a.js
5+
var variable = {};
6+
variable.a = 0;
7+
8+
class C {
9+
initializedMember = {};
10+
constructor() {
11+
this.member = {};
12+
this.member.a = 0;
13+
}
14+
}
15+
16+
var obj = {
17+
property: {}
18+
};
19+
20+
obj.property.a = 0;
21+
22+
var arr = [{}];
23+
24+
function getObj() {
25+
return {};
26+
}
27+
28+
29+
// @filename: b.ts
30+
variable.a = 1;
31+
(new C()).member.a = 1;
32+
(new C()).initializedMember.a = 1;
33+
obj.property.a = 1;
34+
arr[0].a = 1;
35+
getObj().a = 1;
36+

0 commit comments

Comments
 (0)