Skip to content

Commit d1e2242

Browse files
author
Andy
authored
Allow to access exports from inside a commonjs module (#17745)
* Allow to access `exports` from inside a commonjs module * Don't contextually type `this` in `exports.f = function() { ... }` * Update test
1 parent 3062c63 commit d1e2242

14 files changed

+194
-57
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,13 @@ namespace ts {
11251125
}
11261126

11271127
if (!result) {
1128+
if (lastLocation) {
1129+
Debug.assert(lastLocation.kind === SyntaxKind.SourceFile);
1130+
if ((lastLocation as SourceFile).commonJsModuleIndicator && name === "exports") {
1131+
return lastLocation.symbol;
1132+
}
1133+
}
1134+
11281135
result = lookup(globals, name, meaning);
11291136
}
11301137

@@ -12885,7 +12892,8 @@ namespace ts {
1288512892
}
1288612893
}
1288712894
}
12888-
if (noImplicitThis || isInJavaScriptFile(func)) {
12895+
const inJs = isInJavaScriptFile(func);
12896+
if (noImplicitThis || inJs) {
1288912897
const containingLiteral = getContainingObjectLiteral(func);
1289012898
if (containingLiteral) {
1289112899
// We have an object literal method. Check if the containing object literal has a contextual type
@@ -12912,10 +12920,20 @@ namespace ts {
1291212920
}
1291312921
// In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the
1291412922
// contextual type for 'this' is 'obj'.
12915-
if (func.parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>func.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
12916-
const target = (<BinaryExpression>func.parent).left;
12923+
const { parent } = func;
12924+
if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operatorToken.kind === SyntaxKind.EqualsToken) {
12925+
const target = (<BinaryExpression>parent).left;
1291712926
if (target.kind === SyntaxKind.PropertyAccessExpression || target.kind === SyntaxKind.ElementAccessExpression) {
12918-
return checkExpressionCached((<PropertyAccessExpression | ElementAccessExpression>target).expression);
12927+
const { expression } = target as PropertyAccessExpression | ElementAccessExpression;
12928+
// Don't contextually type `this` as `exports` in `exports.Point = function(x, y) { this.x = x; this.y = y; }`
12929+
if (inJs && isIdentifier(expression)) {
12930+
const sourceFile = getSourceFileOfNode(parent);
12931+
if (sourceFile.commonJsModuleIndicator && getResolvedSymbol(expression) === sourceFile.symbol) {
12932+
return undefined;
12933+
}
12934+
}
12935+
12936+
return checkExpressionCached(expression);
1291912937
}
1292012938
}
1292112939
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=== /a.js ===
2+
exports.x = 0;
3+
>exports.x : Symbol(x, Decl(a.js, 0, 0))
4+
>exports : Symbol(x, Decl(a.js, 0, 0))
5+
>x : Symbol(x, Decl(a.js, 0, 0))
6+
7+
exports.x;
8+
>exports.x : Symbol(x, Decl(a.js, 0, 0))
9+
>exports : Symbol("/a", Decl(a.js, 0, 0))
10+
>x : Symbol(x, Decl(a.js, 0, 0))
11+
12+
// Works nested
13+
{
14+
// 'exports' does not provide a contextual type to a function-class
15+
exports.Cls = function() {
16+
>exports.Cls : Symbol(Cls, Decl(a.js, 4, 1))
17+
>exports : Symbol(Cls, Decl(a.js, 4, 1))
18+
>Cls : Symbol(Cls, Decl(a.js, 4, 1))
19+
20+
this.x = 0;
21+
>x : Symbol((Anonymous function).x, Decl(a.js, 6, 30))
22+
}
23+
}
24+
25+
const instance = new exports.Cls();
26+
>instance : Symbol(instance, Decl(a.js, 11, 5))
27+
>exports.Cls : Symbol(Cls, Decl(a.js, 4, 1))
28+
>exports : Symbol("/a", Decl(a.js, 0, 0))
29+
>Cls : Symbol(Cls, Decl(a.js, 4, 1))
30+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
=== /a.js ===
2+
exports.x = 0;
3+
>exports.x = 0 : 0
4+
>exports.x : number
5+
>exports : typeof "/a"
6+
>x : number
7+
>0 : 0
8+
9+
exports.x;
10+
>exports.x : number
11+
>exports : typeof "/a"
12+
>x : number
13+
14+
// Works nested
15+
{
16+
// 'exports' does not provide a contextual type to a function-class
17+
exports.Cls = function() {
18+
>exports.Cls = function() { this.x = 0; } : () => void
19+
>exports.Cls : () => void
20+
>exports : typeof "/a"
21+
>Cls : () => void
22+
>function() { this.x = 0; } : () => void
23+
24+
this.x = 0;
25+
>this.x = 0 : 0
26+
>this.x : any
27+
>this : any
28+
>x : any
29+
>0 : 0
30+
}
31+
}
32+
33+
const instance = new exports.Cls();
34+
>instance : { x: number; }
35+
>new exports.Cls() : { x: number; }
36+
>exports.Cls : () => void
37+
>exports : typeof "/a"
38+
>Cls : () => void
39+

tests/baselines/reference/jsFileCompilationExternalPackageError.symbols

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var a = 10;
1717

1818
=== tests/cases/compiler/node_modules/c.js ===
1919
exports.a = 10;
20+
>exports.a : Symbol(a, Decl(c.js, 0, 0))
2021
>exports : Symbol(a, Decl(c.js, 0, 0))
2122
>a : Symbol(a, Decl(c.js, 0, 0))
2223

tests/baselines/reference/jsFileCompilationExternalPackageError.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ var a = 10;
2121
=== tests/cases/compiler/node_modules/c.js ===
2222
exports.a = 10;
2323
>exports.a = 10 : 10
24-
>exports.a : any
25-
>exports : any
26-
>a : any
24+
>exports.a : number
25+
>exports : typeof "tests/cases/compiler/node_modules/c"
26+
>a : number
2727
>10 : 10
2828

2929
c = 10;

tests/baselines/reference/moduleExportAlias.symbols

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,15 @@ b.func20;
106106
=== tests/cases/conformance/salsa/b.js ===
107107
var exportsAlias = exports;
108108
>exportsAlias : Symbol(exportsAlias, Decl(b.js, 0, 3))
109+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
109110

110111
exportsAlias.func1 = function () { };
112+
>exportsAlias.func1 : Symbol(func1, Decl(b.js, 0, 27))
111113
>exportsAlias : Symbol(exportsAlias, Decl(b.js, 0, 3))
114+
>func1 : Symbol(func1, Decl(b.js, 0, 27))
112115

113116
exports.func2 = function () { };
117+
>exports.func2 : Symbol(func2, Decl(b.js, 1, 37))
114118
>exports : Symbol(func2, Decl(b.js, 1, 37))
115119
>func2 : Symbol(func2, Decl(b.js, 1, 37))
116120

@@ -126,25 +130,32 @@ module.exports.func4 = function () { };
126130

127131
var multipleDeclarationAlias1 = exports = module.exports;
128132
>multipleDeclarationAlias1 : Symbol(multipleDeclarationAlias1, Decl(b.js, 8, 3))
133+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
129134

130135
multipleDeclarationAlias1.func5 = function () { };
131136
>multipleDeclarationAlias1 : Symbol(multipleDeclarationAlias1, Decl(b.js, 8, 3))
132137

133138
var multipleDeclarationAlias2 = module.exports = exports;
134139
>multipleDeclarationAlias2 : Symbol(multipleDeclarationAlias2, Decl(b.js, 11, 3))
140+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
135141

136142
multipleDeclarationAlias2.func6 = function () { };
143+
>multipleDeclarationAlias2.func6 : Symbol(func6, Decl(b.js, 11, 57))
137144
>multipleDeclarationAlias2 : Symbol(multipleDeclarationAlias2, Decl(b.js, 11, 3))
145+
>func6 : Symbol(func6, Decl(b.js, 11, 57))
138146

139147
var someOtherVariable;
140148
>someOtherVariable : Symbol(someOtherVariable, Decl(b.js, 14, 3))
141149

142150
var multipleDeclarationAlias3 = someOtherVariable = exports;
143151
>multipleDeclarationAlias3 : Symbol(multipleDeclarationAlias3, Decl(b.js, 15, 3))
144152
>someOtherVariable : Symbol(someOtherVariable, Decl(b.js, 14, 3))
153+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
145154

146155
multipleDeclarationAlias3.func7 = function () { };
156+
>multipleDeclarationAlias3.func7 : Symbol(func7, Decl(b.js, 15, 60))
147157
>multipleDeclarationAlias3 : Symbol(multipleDeclarationAlias3, Decl(b.js, 15, 3))
158+
>func7 : Symbol(func7, Decl(b.js, 15, 60))
148159

149160
var multipleDeclarationAlias4 = someOtherVariable = module.exports;
150161
>multipleDeclarationAlias4 : Symbol(multipleDeclarationAlias4, Decl(b.js, 18, 3))
@@ -155,20 +166,24 @@ multipleDeclarationAlias4.func8 = function () { };
155166

156167
var multipleDeclarationAlias5 = module.exports = exports = {};
157168
>multipleDeclarationAlias5 : Symbol(multipleDeclarationAlias5, Decl(b.js, 21, 3))
169+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
158170

159171
multipleDeclarationAlias5.func9 = function () { };
160172
>multipleDeclarationAlias5 : Symbol(multipleDeclarationAlias5, Decl(b.js, 21, 3))
161173

162174
var multipleDeclarationAlias6 = exports = module.exports = {};
163175
>multipleDeclarationAlias6 : Symbol(multipleDeclarationAlias6, Decl(b.js, 24, 3))
176+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
164177

165178
multipleDeclarationAlias6.func10 = function () { };
166179
>multipleDeclarationAlias6 : Symbol(multipleDeclarationAlias6, Decl(b.js, 24, 3))
167180

168181
exports = module.exports = someOtherVariable = {};
182+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
169183
>someOtherVariable : Symbol(someOtherVariable, Decl(b.js, 14, 3))
170184

171185
exports.func11 = function () { };
186+
>exports.func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
172187
>exports : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
173188
>func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
174189

@@ -177,9 +192,11 @@ module.exports.func12 = function () { };
177192
>func12 : Symbol(func12, Decl(b.js, 28, 33), Decl(b.js, 32, 33))
178193

179194
exports = module.exports = someOtherVariable = {};
195+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
180196
>someOtherVariable : Symbol(someOtherVariable, Decl(b.js, 14, 3))
181197

182198
exports.func11 = function () { };
199+
>exports.func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
183200
>exports : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
184201
>func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
185202

@@ -188,7 +205,10 @@ module.exports.func12 = function () { };
188205
>func12 : Symbol(func12, Decl(b.js, 28, 33), Decl(b.js, 32, 33))
189206

190207
exports = module.exports = {};
208+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
209+
191210
exports.func13 = function () { };
211+
>exports.func13 : Symbol(func13, Decl(b.js, 35, 30))
192212
>exports : Symbol(func13, Decl(b.js, 35, 30))
193213
>func13 : Symbol(func13, Decl(b.js, 35, 30))
194214

@@ -197,7 +217,10 @@ module.exports.func14 = function () { };
197217
>func14 : Symbol(func14, Decl(b.js, 36, 33))
198218

199219
exports = module.exports = {};
220+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
221+
200222
exports.func15 = function () { };
223+
>exports.func15 : Symbol(func15, Decl(b.js, 39, 30))
201224
>exports : Symbol(func15, Decl(b.js, 39, 30))
202225
>func15 : Symbol(func15, Decl(b.js, 39, 30))
203226

@@ -206,7 +229,10 @@ module.exports.func16 = function () { };
206229
>func16 : Symbol(func16, Decl(b.js, 40, 33))
207230

208231
module.exports = exports = {};
232+
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))
233+
209234
exports.func17 = function () { };
235+
>exports.func17 : Symbol(func17, Decl(b.js, 43, 30))
210236
>exports : Symbol(func17, Decl(b.js, 43, 30))
211237
>func17 : Symbol(func17, Decl(b.js, 43, 30))
212238

@@ -216,6 +242,7 @@ module.exports.func18 = function () { };
216242

217243
module.exports = {};
218244
exports.func19 = function () { };
245+
>exports.func19 : Symbol(func19, Decl(b.js, 47, 20))
219246
>exports : Symbol(func19, Decl(b.js, 47, 20))
220247
>func19 : Symbol(func19, Decl(b.js, 47, 20))
221248

0 commit comments

Comments
 (0)