Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,13 @@ namespace ts {
}

if (!result) {
if (lastLocation) {
Debug.assert(lastLocation.kind === SyntaxKind.SourceFile);
if ((lastLocation as SourceFile).commonJsModuleIndicator && name === "exports") {
return lastLocation.symbol;
}
}

result = lookup(globals, name, meaning);
}

Expand Down Expand Up @@ -12812,7 +12819,8 @@ namespace ts {
}
}
}
if (noImplicitThis || isInJavaScriptFile(func)) {
const inJs = isInJavaScriptFile(func);
if (noImplicitThis || inJs) {
const containingLiteral = getContainingObjectLiteral(func);
if (containingLiteral) {
// We have an object literal method. Check if the containing object literal has a contextual type
Expand All @@ -12839,10 +12847,20 @@ namespace ts {
}
// In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the
// contextual type for 'this' is 'obj'.
if (func.parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>func.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
const target = (<BinaryExpression>func.parent).left;
const { parent } = func;
if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operatorToken.kind === SyntaxKind.EqualsToken) {
const target = (<BinaryExpression>parent).left;
if (target.kind === SyntaxKind.PropertyAccessExpression || target.kind === SyntaxKind.ElementAccessExpression) {
return checkExpressionCached((<PropertyAccessExpression | ElementAccessExpression>target).expression);
const { expression } = target as PropertyAccessExpression | ElementAccessExpression;
// Don't contextually type `this` as `exports` in `exports.Point = function(x, y) { this.x = x; this.y = y; }`
if (inJs && isIdentifier(expression)) {
const sourceFile = getSourceFileOfNode(parent);
if (sourceFile.commonJsModuleIndicator && getResolvedSymbol(expression) === sourceFile.symbol) {
return undefined;
}
}

return checkExpressionCached(expression);
}
}
}
Expand Down
30 changes: 30 additions & 0 deletions tests/baselines/reference/commonjsAccessExports.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
=== /a.js ===
exports.x = 0;
>exports.x : Symbol(x, Decl(a.js, 0, 0))
>exports : Symbol(x, Decl(a.js, 0, 0))
>x : Symbol(x, Decl(a.js, 0, 0))

exports.x;
>exports.x : Symbol(x, Decl(a.js, 0, 0))
>exports : Symbol("/a", Decl(a.js, 0, 0))
>x : Symbol(x, Decl(a.js, 0, 0))

// Works nested
{
// 'exports' does not provide a contextual type to a function-class
exports.Cls = function() {
>exports.Cls : Symbol(Cls, Decl(a.js, 4, 1))
>exports : Symbol(Cls, Decl(a.js, 4, 1))
>Cls : Symbol(Cls, Decl(a.js, 4, 1))

this.x = 0;
>x : Symbol((Anonymous function).x, Decl(a.js, 6, 30))
}
}

const instance = new exports.Cls();
>instance : Symbol(instance, Decl(a.js, 11, 5))
>exports.Cls : Symbol(Cls, Decl(a.js, 4, 1))
>exports : Symbol("/a", Decl(a.js, 0, 0))
>Cls : Symbol(Cls, Decl(a.js, 4, 1))

39 changes: 39 additions & 0 deletions tests/baselines/reference/commonjsAccessExports.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
=== /a.js ===
exports.x = 0;
>exports.x = 0 : 0
>exports.x : number
>exports : typeof "/a"
>x : number
>0 : 0

exports.x;
>exports.x : number
>exports : typeof "/a"
>x : number

// Works nested
{
// 'exports' does not provide a contextual type to a function-class
exports.Cls = function() {
>exports.Cls = function() { this.x = 0; } : () => void
>exports.Cls : () => void
>exports : typeof "/a"
>Cls : () => void
>function() { this.x = 0; } : () => void

this.x = 0;
>this.x = 0 : 0
>this.x : any
>this : any
>x : any
>0 : 0
}
}

const instance = new exports.Cls();
>instance : { x: number; }
>new exports.Cls() : { x: number; }
>exports.Cls : () => void
>exports : typeof "/a"
>Cls : () => void

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var a = 10;

=== tests/cases/compiler/node_modules/c.js ===
exports.a = 10;
>exports.a : Symbol(a, Decl(c.js, 0, 0))
>exports : Symbol(a, Decl(c.js, 0, 0))
>a : Symbol(a, Decl(c.js, 0, 0))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ var a = 10;
=== tests/cases/compiler/node_modules/c.js ===
exports.a = 10;
>exports.a = 10 : 10
>exports.a : any
>exports : any
>a : any
>exports.a : number
>exports : typeof "tests/cases/compiler/node_modules/c"
>a : number
>10 : 10

c = 10;
Expand Down
27 changes: 27 additions & 0 deletions tests/baselines/reference/moduleExportAlias.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,15 @@ b.func20;
=== tests/cases/conformance/salsa/b.js ===
var exportsAlias = exports;
>exportsAlias : Symbol(exportsAlias, Decl(b.js, 0, 3))
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))

exportsAlias.func1 = function () { };
>exportsAlias.func1 : Symbol(func1, Decl(b.js, 0, 27))
>exportsAlias : Symbol(exportsAlias, Decl(b.js, 0, 3))
>func1 : Symbol(func1, Decl(b.js, 0, 27))

exports.func2 = function () { };
>exports.func2 : Symbol(func2, Decl(b.js, 1, 37))
>exports : Symbol(func2, Decl(b.js, 1, 37))
>func2 : Symbol(func2, Decl(b.js, 1, 37))

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

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

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

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

multipleDeclarationAlias2.func6 = function () { };
>multipleDeclarationAlias2.func6 : Symbol(func6, Decl(b.js, 11, 57))
>multipleDeclarationAlias2 : Symbol(multipleDeclarationAlias2, Decl(b.js, 11, 3))
>func6 : Symbol(func6, Decl(b.js, 11, 57))

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

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

multipleDeclarationAlias3.func7 = function () { };
>multipleDeclarationAlias3.func7 : Symbol(func7, Decl(b.js, 15, 60))
>multipleDeclarationAlias3 : Symbol(multipleDeclarationAlias3, Decl(b.js, 15, 3))
>func7 : Symbol(func7, Decl(b.js, 15, 60))

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

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

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

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

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

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

exports.func11 = function () { };
>exports.func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
>exports : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
>func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))

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

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

exports.func11 = function () { };
>exports.func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
>exports : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))
>func11 : Symbol(func11, Decl(b.js, 27, 50), Decl(b.js, 31, 50))

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

exports = module.exports = {};
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))

exports.func13 = function () { };
>exports.func13 : Symbol(func13, Decl(b.js, 35, 30))
>exports : Symbol(func13, Decl(b.js, 35, 30))
>func13 : Symbol(func13, Decl(b.js, 35, 30))

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

exports = module.exports = {};
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))

exports.func15 = function () { };
>exports.func15 : Symbol(func15, Decl(b.js, 39, 30))
>exports : Symbol(func15, Decl(b.js, 39, 30))
>func15 : Symbol(func15, Decl(b.js, 39, 30))

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

module.exports = exports = {};
>exports : Symbol("tests/cases/conformance/salsa/b", Decl(b.js, 0, 0))

exports.func17 = function () { };
>exports.func17 : Symbol(func17, Decl(b.js, 43, 30))
>exports : Symbol(func17, Decl(b.js, 43, 30))
>func17 : Symbol(func17, Decl(b.js, 43, 30))

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

module.exports = {};
exports.func19 = function () { };
>exports.func19 : Symbol(func19, Decl(b.js, 47, 20))
>exports : Symbol(func19, Decl(b.js, 47, 20))
>func19 : Symbol(func19, Decl(b.js, 47, 20))

Expand Down
Loading