Skip to content

Commit d696253

Browse files
Andaristsnovader
authored andcommitted
Fixed declaration emit for expando properties on function declarations declared using element access expressions (microsoft#55183)
1 parent 701d114 commit d696253

File tree

7 files changed

+665
-5
lines changed

7 files changed

+665
-5
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ import {
505505
isEnumDeclaration,
506506
isEnumMember,
507507
isExclusivelyTypeOnlyImportOrExport,
508+
isExpandoPropertyDeclaration,
508509
isExportAssignment,
509510
isExportDeclaration,
510511
isExportsIdentifier,
@@ -8174,6 +8175,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
81748175
const type = checkExpression(name.expression);
81758176
return !!(type.flags & TypeFlags.StringLike);
81768177
}
8178+
if (isElementAccessExpression(name)) {
8179+
const type = checkExpression(name.argumentExpression);
8180+
return !!(type.flags & TypeFlags.StringLike);
8181+
}
81778182
return isStringLiteral(name);
81788183
}
81798184

@@ -47200,7 +47205,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4720047205
if (!symbol || !(symbol.flags & SymbolFlags.Function)) {
4720147206
return false;
4720247207
}
47203-
return !!forEachEntry(getExportsOfSymbol(symbol), p => p.flags & SymbolFlags.Value && p.valueDeclaration && isPropertyAccessExpression(p.valueDeclaration));
47208+
return !!forEachEntry(getExportsOfSymbol(symbol), p => p.flags & SymbolFlags.Value && isExpandoPropertyDeclaration(p.valueDeclaration));
4720447209
}
4720547210

4720647211
function getPropertiesOfContainerFunction(node: Declaration): Symbol[] {

src/compiler/transformers/declarations.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,15 @@ import {
9595
isAnyImportSyntax,
9696
isArray,
9797
isArrayBindingElement,
98-
isBinaryExpression,
9998
isBindingElement,
10099
isBindingPattern,
101100
isClassDeclaration,
102101
isClassElement,
103102
isComputedPropertyName,
104103
isDeclaration,
105-
isElementAccessExpression,
106104
isEntityName,
107105
isEntityNameExpression,
106+
isExpandoPropertyDeclaration,
108107
isExportAssignment,
109108
isExportDeclaration,
110109
isExpressionWithTypeArguments,
@@ -134,7 +133,6 @@ import {
134133
isNightly,
135134
isOmittedExpression,
136135
isPrivateIdentifier,
137-
isPropertyAccessExpression,
138136
isPropertySignature,
139137
isSemicolonClassElement,
140138
isSetAccessorDeclaration,
@@ -1540,7 +1538,7 @@ export function transformDeclarations(context: TransformationContext) {
15401538
fakespace.symbol = props[0].parent!;
15411539
const exportMappings: [Identifier, string][] = [];
15421540
let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => {
1543-
if (!p.valueDeclaration || !(isPropertyAccessExpression(p.valueDeclaration) || isElementAccessExpression(p.valueDeclaration) || isBinaryExpression(p.valueDeclaration))) {
1541+
if (!isExpandoPropertyDeclaration(p.valueDeclaration)) {
15441542
return undefined;
15451543
}
15461544
const nameStr = unescapeLeadingUnderscores(p.escapedName);

src/compiler/utilities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10461,3 +10461,8 @@ export function getPropertyNameFromType(type: StringLiteralType | NumberLiteralT
1046110461
}
1046210462
return Debug.fail();
1046310463
}
10464+
10465+
/** @internal */
10466+
export function isExpandoPropertyDeclaration(declaration: Declaration | undefined): declaration is PropertyAccessExpression | ElementAccessExpression | BinaryExpression {
10467+
return !!declaration && (isPropertyAccessExpression(declaration) || isElementAccessExpression(declaration) || isBinaryExpression(declaration));
10468+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
//// [tests/cases/compiler/declarationEmitLateBoundAssignments2.ts] ////
2+
3+
//// [declarationEmitLateBoundAssignments2.ts]
4+
// https://github.com/microsoft/TypeScript/issues/54811
5+
6+
const c = "C"
7+
const num = 1
8+
const numStr = "10"
9+
const withWhitespace = "foo bar"
10+
const emoji = "🤷‍♂️"
11+
12+
export function decl() {}
13+
decl["B"] = 'foo'
14+
15+
export function decl2() {}
16+
decl2[c] = 0
17+
18+
export function decl3() {}
19+
decl3[77] = 0
20+
21+
export function decl4() {}
22+
decl4[num] = 0
23+
24+
export function decl5() {}
25+
decl5["101"] = 0
26+
27+
export function decl6() {}
28+
decl6[numStr] = 0
29+
30+
export function decl7() {}
31+
decl7["qwe rty"] = 0
32+
33+
export function decl8() {}
34+
decl8[withWhitespace] = 0
35+
36+
export function decl9() {}
37+
decl9["🤪"] = 0
38+
39+
export function decl10() {}
40+
decl10[emoji] = 0
41+
42+
export const arrow = () => {}
43+
arrow["B"] = 'bar'
44+
45+
export const arrow2 = () => {}
46+
arrow2[c] = 100
47+
48+
export const arrow3 = () => {}
49+
arrow3[77] = 0
50+
51+
export const arrow4 = () => {}
52+
arrow4[num] = 0
53+
54+
export const arrow5 = () => {}
55+
arrow5["101"] = 0
56+
57+
export const arrow6 = () => {}
58+
arrow6[numStr] = 0
59+
60+
export const arrow7 = () => {}
61+
arrow7["qwe rty"] = 0
62+
63+
export const arrow8 = () => {}
64+
arrow8[withWhitespace] = 0
65+
66+
export const arrow9 = () => {}
67+
arrow9["🤪"] = 0
68+
69+
export const arrow10 = () => {}
70+
arrow10[emoji] = 0
71+
72+
73+
//// [declarationEmitLateBoundAssignments2.js]
74+
// https://github.com/microsoft/TypeScript/issues/54811
75+
const c = "C";
76+
const num = 1;
77+
const numStr = "10";
78+
const withWhitespace = "foo bar";
79+
const emoji = "🤷‍♂️";
80+
export function decl() { }
81+
decl["B"] = 'foo';
82+
export function decl2() { }
83+
decl2[c] = 0;
84+
export function decl3() { }
85+
decl3[77] = 0;
86+
export function decl4() { }
87+
decl4[num] = 0;
88+
export function decl5() { }
89+
decl5["101"] = 0;
90+
export function decl6() { }
91+
decl6[numStr] = 0;
92+
export function decl7() { }
93+
decl7["qwe rty"] = 0;
94+
export function decl8() { }
95+
decl8[withWhitespace] = 0;
96+
export function decl9() { }
97+
decl9["🤪"] = 0;
98+
export function decl10() { }
99+
decl10[emoji] = 0;
100+
export const arrow = () => { };
101+
arrow["B"] = 'bar';
102+
export const arrow2 = () => { };
103+
arrow2[c] = 100;
104+
export const arrow3 = () => { };
105+
arrow3[77] = 0;
106+
export const arrow4 = () => { };
107+
arrow4[num] = 0;
108+
export const arrow5 = () => { };
109+
arrow5["101"] = 0;
110+
export const arrow6 = () => { };
111+
arrow6[numStr] = 0;
112+
export const arrow7 = () => { };
113+
arrow7["qwe rty"] = 0;
114+
export const arrow8 = () => { };
115+
arrow8[withWhitespace] = 0;
116+
export const arrow9 = () => { };
117+
arrow9["🤪"] = 0;
118+
export const arrow10 = () => { };
119+
arrow10[emoji] = 0;
120+
121+
122+
//// [declarationEmitLateBoundAssignments2.d.ts]
123+
export declare function decl(): void;
124+
export declare namespace decl {
125+
var B: string;
126+
}
127+
export declare function decl2(): void;
128+
export declare namespace decl2 {
129+
var C: number;
130+
}
131+
export declare function decl3(): void;
132+
export declare namespace decl3 { }
133+
export declare function decl4(): void;
134+
export declare namespace decl4 { }
135+
export declare function decl5(): void;
136+
export declare namespace decl5 { }
137+
export declare function decl6(): void;
138+
export declare namespace decl6 { }
139+
export declare function decl7(): void;
140+
export declare namespace decl7 { }
141+
export declare function decl8(): void;
142+
export declare namespace decl8 { }
143+
export declare function decl9(): void;
144+
export declare namespace decl9 { }
145+
export declare function decl10(): void;
146+
export declare namespace decl10 { }
147+
export declare const arrow: {
148+
(): void;
149+
B: string;
150+
};
151+
export declare const arrow2: {
152+
(): void;
153+
C: number;
154+
};
155+
export declare const arrow3: {
156+
(): void;
157+
77: number;
158+
};
159+
export declare const arrow4: {
160+
(): void;
161+
1: number;
162+
};
163+
export declare const arrow5: {
164+
(): void;
165+
"101": number;
166+
};
167+
export declare const arrow6: {
168+
(): void;
169+
"10": number;
170+
};
171+
export declare const arrow7: {
172+
(): void;
173+
"qwe rty": number;
174+
};
175+
export declare const arrow8: {
176+
(): void;
177+
"foo bar": number;
178+
};
179+
export declare const arrow9: {
180+
(): void;
181+
"\uD83E\uDD2A": number;
182+
};
183+
export declare const arrow10: {
184+
(): void;
185+
"\uD83E\uDD37\u200D\u2642\uFE0F": number;
186+
};

0 commit comments

Comments
 (0)