Skip to content

Commit c1ea85f

Browse files
committed
Merge pull request microsoft#5588 from Microsoft/reexport-default-export
Reexport default export
2 parents 9c1796f + 9472c0b commit c1ea85f

5 files changed

Lines changed: 113 additions & 22 deletions

File tree

src/compiler/checker.ts

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -486,9 +486,19 @@ namespace ts {
486486
if (location.kind === SyntaxKind.SourceFile ||
487487
(location.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>location).name.kind === SyntaxKind.StringLiteral)) {
488488

489-
// It's an external module. Because of module/namespace merging, a module's exports are in scope,
490-
// yet we never want to treat an export specifier as putting a member in scope. Therefore,
491-
// if the name we find is purely an export specifier, it is not actually considered in scope.
489+
// It's an external module. First see if the module has an export default and if the local
490+
// name of that export default matches.
491+
if (result = moduleExports["default"]) {
492+
const localSymbol = getLocalSymbolForExportDefault(result);
493+
if (localSymbol && (result.flags & meaning) && localSymbol.name === name) {
494+
break loop;
495+
}
496+
result = undefined;
497+
}
498+
499+
// Because of module/namespace merging, a module's exports are in scope,
500+
// yet we never want to treat an export specifier as putting a member in scope.
501+
// Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
492502
// Two things to note about this:
493503
// 1. We have to check this without calling getSymbol. The problem with calling getSymbol
494504
// on an export specifier is that it might find the export specifier itself, and try to
@@ -502,13 +512,6 @@ namespace ts {
502512
getDeclarationOfKind(moduleExports[name], SyntaxKind.ExportSpecifier)) {
503513
break;
504514
}
505-
506-
result = moduleExports["default"];
507-
const localSymbol = getLocalSymbolForExportDefault(result);
508-
if (result && localSymbol && (result.flags & meaning) && localSymbol.name === name) {
509-
break loop;
510-
}
511-
result = undefined;
512515
}
513516

514517
if (result = getSymbol(moduleExports, name, meaning & SymbolFlags.ModuleMember)) {
@@ -4201,12 +4204,12 @@ namespace ts {
42014204
// We only support expressions that are simple qualified names. For other expressions this produces undefined.
42024205
const typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (<TypeReferenceNode>node).typeName :
42034206
isSupportedExpressionWithTypeArguments(<ExpressionWithTypeArguments>node) ? (<ExpressionWithTypeArguments>node).expression :
4204-
undefined;
4207+
undefined;
42054208
const symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol;
42064209
const type = symbol === unknownSymbol ? unknownType :
42074210
symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) :
4208-
symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) :
4209-
getTypeFromNonGenericTypeReference(node, symbol);
4211+
symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) :
4212+
getTypeFromNonGenericTypeReference(node, symbol);
42104213
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
42114214
// type reference in checkTypeReferenceOrExpressionWithTypeArguments.
42124215
links.resolvedSymbol = symbol;
@@ -11446,7 +11449,7 @@ namespace ts {
1144611449

1144711450
// Abstract methods can't have an implementation -- in particular, they don't need one.
1144811451
if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body &&
11449-
!(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) ) {
11452+
!(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract)) {
1145011453
reportImplementationExpectedError(lastSeenNonAmbientDeclaration);
1145111454
}
1145211455

@@ -14380,8 +14383,8 @@ namespace ts {
1438014383
if (className) {
1438114384
copySymbol(location.symbol, meaning);
1438214385
}
14383-
// fall through; this fall-through is necessary because we would like to handle
14384-
// type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration
14386+
// fall through; this fall-through is necessary because we would like to handle
14387+
// type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration
1438514388
case SyntaxKind.ClassDeclaration:
1438614389
case SyntaxKind.InterfaceDeclaration:
1438714390
// If we didn't come from static member of class or interface,
@@ -14537,8 +14540,8 @@ namespace ts {
1453714540
return resolveEntityName(<EntityName>entityName, meaning);
1453814541
}
1453914542
else if ((entityName.parent.kind === SyntaxKind.JsxOpeningElement) ||
14540-
(entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) ||
14541-
(entityName.parent.kind === SyntaxKind.JsxClosingElement)) {
14543+
(entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) ||
14544+
(entityName.parent.kind === SyntaxKind.JsxClosingElement)) {
1454214545
return getJsxElementTagSymbol(<JsxOpeningLikeElement>entityName.parent);
1454314546
}
1454414547
else if (isExpression(entityName)) {
@@ -14605,8 +14608,8 @@ namespace ts {
1460514608
: getSymbolOfPartOfRightHandSideOfImportEquals(<Identifier>node);
1460614609
}
1460714610
else if (node.parent.kind === SyntaxKind.BindingElement &&
14608-
node.parent.parent.kind === SyntaxKind.ObjectBindingPattern &&
14609-
node === (<BindingElement>node.parent).propertyName) {
14611+
node.parent.parent.kind === SyntaxKind.ObjectBindingPattern &&
14612+
node === (<BindingElement>node.parent).propertyName) {
1461014613
const typeOfPattern = getTypeOfNode(node.parent.parent);
1461114614
const propertyDeclaration = typeOfPattern && getPropertyOfType(typeOfPattern, (<Identifier>node).text);
1461214615

@@ -14643,7 +14646,7 @@ namespace ts {
1464314646
(<ImportDeclaration>node.parent).moduleSpecifier === node)) {
1464414647
return resolveExternalModuleName(node, <LiteralExpression>node);
1464514648
}
14646-
// Fall through
14649+
// Fall through
1464714650

1464814651
case SyntaxKind.NumericLiteral:
1464914652
// index access
@@ -14839,7 +14842,7 @@ namespace ts {
1483914842
if (links.isNestedRedeclaration === undefined) {
1484014843
const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration);
1484114844
links.isNestedRedeclaration = isStatementWithLocals(container) &&
14842-
!!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
14845+
!!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
1484314846
}
1484414847
return links.isNestedRedeclaration;
1484514848
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [tests/cases/conformance/es6/modules/reExportDefaultExport.ts] ////
2+
3+
//// [m1.ts]
4+
5+
export default function f() {
6+
}
7+
export {f};
8+
9+
10+
//// [m2.ts]
11+
import foo from "./m1";
12+
import {f} from "./m1";
13+
14+
f();
15+
foo();
16+
17+
//// [m1.js]
18+
function f() {
19+
}
20+
Object.defineProperty(exports, "__esModule", { value: true });
21+
exports.default = f;
22+
exports.f = f;
23+
//// [m2.js]
24+
var m1_1 = require("./m1");
25+
var m1_2 = require("./m1");
26+
m1_2.f();
27+
m1_1.default();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/es6/modules/m1.ts ===
2+
3+
export default function f() {
4+
>f : Symbol(f, Decl(m1.ts, 0, 0))
5+
}
6+
export {f};
7+
>f : Symbol(f, Decl(m1.ts, 3, 8))
8+
9+
10+
=== tests/cases/conformance/es6/modules/m2.ts ===
11+
import foo from "./m1";
12+
>foo : Symbol(foo, Decl(m2.ts, 0, 6))
13+
14+
import {f} from "./m1";
15+
>f : Symbol(f, Decl(m2.ts, 1, 8))
16+
17+
f();
18+
>f : Symbol(f, Decl(m2.ts, 1, 8))
19+
20+
foo();
21+
>foo : Symbol(foo, Decl(m2.ts, 0, 6))
22+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
=== tests/cases/conformance/es6/modules/m1.ts ===
2+
3+
export default function f() {
4+
>f : () => void
5+
}
6+
export {f};
7+
>f : () => void
8+
9+
10+
=== tests/cases/conformance/es6/modules/m2.ts ===
11+
import foo from "./m1";
12+
>foo : () => void
13+
14+
import {f} from "./m1";
15+
>f : () => void
16+
17+
f();
18+
>f() : void
19+
>f : () => void
20+
21+
foo();
22+
>foo() : void
23+
>foo : () => void
24+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @module: commonjs
2+
// @target: ES5
3+
4+
// @filename: m1.ts
5+
export default function f() {
6+
}
7+
export {f};
8+
9+
10+
// @filename: m2.ts
11+
import foo from "./m1";
12+
import {f} from "./m1";
13+
14+
f();
15+
foo();

0 commit comments

Comments
 (0)