Skip to content

Commit 1a69f78

Browse files
author
Andy
authored
Fix bug: Ensure export = symbol always has a valueDeclaration (#26973)
1 parent cc7bfc0 commit 1a69f78

6 files changed

+47
-24
lines changed

src/compiler/binder.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,17 @@ namespace ts {
234234
}
235235

236236
if (symbolFlags & SymbolFlags.Value) {
237-
const { valueDeclaration } = symbol;
238-
if (!valueDeclaration ||
239-
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
240-
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
241-
// other kinds of value declarations take precedence over modules and assignment declarations
242-
symbol.valueDeclaration = node;
243-
}
237+
setValueDeclaration(symbol, node);
238+
}
239+
}
240+
241+
function setValueDeclaration(symbol: Symbol, node: Declaration): void {
242+
const { valueDeclaration } = symbol;
243+
if (!valueDeclaration ||
244+
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
245+
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
246+
// other kinds of value declarations take precedence over modules and assignment declarations
247+
symbol.valueDeclaration = node;
244248
}
245249
}
246250

@@ -2286,14 +2290,19 @@ namespace ts {
22862290
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)!);
22872291
}
22882292
else {
2289-
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node)
2293+
const flags = exportAssignmentIsAlias(node)
22902294
// An export default clause with an EntityNameExpression or a class expression exports all meanings of that identifier or expression;
22912295
? SymbolFlags.Alias
22922296
// An export default clause with any other expression exports a value
22932297
: SymbolFlags.Property;
22942298
// If there is an `export default x;` alias declaration, can't `export default` anything else.
22952299
// (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.)
2296-
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
2300+
const symbol = declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
2301+
2302+
if (node.isExportEquals) {
2303+
// Will be an error later, since the module already has other exports. Just make sure this has a valueDeclaration set.
2304+
setValueDeclaration(symbol, node);
2305+
}
22972306
}
22982307
}
22992308

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
tests/cases/compiler/errorForConflictingExportEqualsValue.ts(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements.
1+
/a.ts(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements.
22

33

4-
==== tests/cases/compiler/errorForConflictingExportEqualsValue.ts (1 errors) ====
4+
==== /a.ts (1 errors) ====
55
export var x;
6-
export = {};
7-
~~~~~~~~~~~~
6+
export = x;
7+
~~~~~~~~~~~
88
!!! error TS2309: An export assignment cannot be used in a module with other exported elements.
9+
import("./a");
910

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
//// [errorForConflictingExportEqualsValue.ts]
1+
//// [a.ts]
22
export var x;
3-
export = {};
3+
export = x;
4+
import("./a");
45

56

6-
//// [errorForConflictingExportEqualsValue.js]
7+
//// [a.js]
78
"use strict";
8-
module.exports = {};
9+
Promise.resolve().then(function () { return require("./a"); });
10+
module.exports = exports.x;
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
=== tests/cases/compiler/errorForConflictingExportEqualsValue.ts ===
1+
=== /a.ts ===
22
export var x;
3-
>x : Symbol(x, Decl(errorForConflictingExportEqualsValue.ts, 0, 10))
3+
>x : Symbol(x, Decl(a.ts, 0, 10))
44

5-
export = {};
5+
export = x;
6+
>x : Symbol(x, Decl(a.ts, 0, 10))
7+
8+
import("./a");
9+
>"./a" : Symbol("/a", Decl(a.ts, 0, 0))
610

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
=== tests/cases/compiler/errorForConflictingExportEqualsValue.ts ===
1+
=== /a.ts ===
22
export var x;
33
>x : any
44

5-
export = {};
6-
>{} : {}
5+
export = x;
6+
>x : any
7+
8+
import("./a");
9+
>import("./a") : Promise<typeof import("/a").x>
10+
>"./a" : "./a"
711

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1+
// @lib: es6
2+
// @Filename: /a.ts
13
export var x;
2-
export = {};
4+
export = x;
5+
import("./a");

0 commit comments

Comments
 (0)