Skip to content

Commit 0365393

Browse files
authored
Don't create expando object literals in TS (microsoft#26525)
Previously, getWidenedTypedFromJSPropertyAssignment was not called for Typescript code. Since property assignments on functions, it is. That meant that property assignments would incorrectly create a JS container for empty object literals in a property assignment, even in Typescript: ```ts const one = () => 1 one.p = {} one.p.q = {} // should not work in Typescript! ``` Now empty object literals never create expando objects in Typescript, because getJSExpandoObjectType requires the declaration to be in a JS file.
1 parent 5e8b63c commit 0365393

File tree

5 files changed

+65
-1
lines changed

5 files changed

+65
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4795,7 +4795,7 @@ namespace ts {
47954795
}
47964796

47974797
function getJSExpandoObjectType(decl: Node, symbol: Symbol, init: Expression | undefined): Type | undefined {
4798-
if (!init || !isObjectLiteralExpression(init) || init.properties.length) {
4798+
if (!isInJavaScriptFile(decl) || !init || !isObjectLiteralExpression(init) || init.properties.length) {
47994799
return undefined;
48004800
}
48014801
const exports = createSymbolTable();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//// [typeFromPropertyAssignment30.ts]
2+
interface Combo {
3+
(): number;
4+
p?: { [s: string]: number };
5+
}
6+
const c: Combo = () => 1
7+
// should not be an expando object, but contextually typed by Combo.p
8+
c.p = {}
9+
10+
11+
12+
//// [typeFromPropertyAssignment30.js]
13+
var c = function () { return 1; };
14+
// should not be an expando object, but contextually typed by Combo.p
15+
c.p = {};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/salsa/typeFromPropertyAssignment30.ts ===
2+
interface Combo {
3+
>Combo : Symbol(Combo, Decl(typeFromPropertyAssignment30.ts, 0, 0))
4+
5+
(): number;
6+
p?: { [s: string]: number };
7+
>p : Symbol(Combo.p, Decl(typeFromPropertyAssignment30.ts, 1, 15))
8+
>s : Symbol(s, Decl(typeFromPropertyAssignment30.ts, 2, 11))
9+
}
10+
const c: Combo = () => 1
11+
>c : Symbol(c, Decl(typeFromPropertyAssignment30.ts, 4, 5), Decl(typeFromPropertyAssignment30.ts, 4, 24))
12+
>Combo : Symbol(Combo, Decl(typeFromPropertyAssignment30.ts, 0, 0))
13+
14+
// should not be an expando object, but contextually typed by Combo.p
15+
c.p = {}
16+
>c.p : Symbol(Combo.p, Decl(typeFromPropertyAssignment30.ts, 1, 15))
17+
>c : Symbol(c, Decl(typeFromPropertyAssignment30.ts, 4, 5), Decl(typeFromPropertyAssignment30.ts, 4, 24))
18+
>p : Symbol(Combo.p, Decl(typeFromPropertyAssignment30.ts, 1, 15))
19+
20+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/conformance/salsa/typeFromPropertyAssignment30.ts ===
2+
interface Combo {
3+
(): number;
4+
p?: { [s: string]: number };
5+
>p : { [s: string]: number; }
6+
>s : string
7+
}
8+
const c: Combo = () => 1
9+
>c : Combo
10+
>() => 1 : { (): number; p: {}; }
11+
>1 : 1
12+
13+
// should not be an expando object, but contextually typed by Combo.p
14+
c.p = {}
15+
>c.p = {} : {}
16+
>c.p : { [s: string]: number; }
17+
>c : Combo
18+
>p : { [s: string]: number; }
19+
>{} : {}
20+
21+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
interface Combo {
2+
(): number;
3+
p?: { [s: string]: number };
4+
}
5+
const c: Combo = () => 1
6+
// should not be an expando object, but contextually typed by Combo.p
7+
c.p = {}
8+

0 commit comments

Comments
 (0)