Skip to content

Commit 2240fbf

Browse files
committed
Merge pull request #2339 from Microsoft/exportDefaultType
Support an optional type annotation on export default statement
2 parents 85cf761 + 696b688 commit 2240fbf

24 files changed

+172
-22
lines changed

src/compiler/binder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ module ts {
505505
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
506506
break;
507507
case SyntaxKind.ExportAssignment:
508-
if ((<ExportAssignment>node).expression.kind === SyntaxKind.Identifier) {
508+
if ((<ExportAssignment>node).expression && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier) {
509509
// An export default clause with an identifier exports all meanings of that identifier
510510
declareSymbol(container.symbol.exports, container.symbol, <Declaration>node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
511511
}

src/compiler/checker.ts

+26-8
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ module ts {
567567
}
568568

569569
function getTargetOfExportAssignment(node: ExportAssignment): Symbol {
570-
return resolveEntityName(<Identifier>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
570+
return node.expression && resolveEntityName(<Identifier>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
571571
}
572572

573573
function getTargetOfImportDeclaration(node: Declaration): Symbol {
@@ -623,7 +623,7 @@ module ts {
623623
if (!links.referenced) {
624624
links.referenced = true;
625625
let node = getDeclarationOfAliasSymbol(symbol);
626-
if (node.kind === SyntaxKind.ExportAssignment) {
626+
if (node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression) {
627627
// export default <symbol>
628628
checkExpressionCached((<ExportAssignment>node).expression);
629629
}
@@ -2073,7 +2073,16 @@ module ts {
20732073
}
20742074
// Handle export default expressions
20752075
if (declaration.kind === SyntaxKind.ExportAssignment) {
2076-
return links.type = checkExpression((<ExportAssignment>declaration).expression);
2076+
var exportAssignment = <ExportAssignment>declaration;
2077+
if (exportAssignment.expression) {
2078+
return links.type = checkExpression(exportAssignment.expression);
2079+
}
2080+
else if (exportAssignment.type) {
2081+
return links.type = getTypeFromTypeNode(exportAssignment.type);
2082+
}
2083+
else {
2084+
return links.type = anyType;
2085+
}
20772086
}
20782087
// Handle variable, parameter or property
20792088
links.type = resolvingType;
@@ -10075,12 +10084,21 @@ module ts {
1007510084
if (!checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) {
1007610085
grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers);
1007710086
}
10078-
if (node.expression.kind === SyntaxKind.Identifier) {
10079-
markExportAsReferenced(node);
10087+
if (node.expression) {
10088+
if (node.expression.kind === SyntaxKind.Identifier) {
10089+
markExportAsReferenced(node);
10090+
}
10091+
else {
10092+
checkExpressionCached(node.expression);
10093+
}
1008010094
}
10081-
else {
10082-
checkExpressionCached(node.expression);
10095+
if (node.type) {
10096+
checkSourceElement(node.type);
10097+
if (!isInAmbientContext(node)) {
10098+
grammarErrorOnFirstToken(node.type, Diagnostics.A_type_annotation_on_an_export_statement_is_only_allowed_in_an_ambient_external_module_declaration);
10099+
}
1008310100
}
10101+
1008410102
checkExternalModuleExports(container);
1008510103
}
1008610104

@@ -10914,7 +10932,7 @@ module ts {
1091410932
}
1091510933

1091610934
function generateNameForExportAssignment(node: ExportAssignment) {
10917-
if (node.expression.kind !== SyntaxKind.Identifier) {
10935+
if (node.expression && node.expression.kind !== SyntaxKind.Identifier) {
1091810936
assignGeneratedName(node, makeUniqueName("default"));
1091910937
}
1092010938
}

src/compiler/diagnosticInformationMap.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ module ts {
158158
An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive: { code: 1198, category: DiagnosticCategory.Error, key: "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive." },
159159
Unterminated_Unicode_escape_sequence: { code: 1199, category: DiagnosticCategory.Error, key: "Unterminated Unicode escape sequence." },
160160
Line_terminator_not_permitted_before_arrow: { code: 1200, category: DiagnosticCategory.Error, key: "Line terminator not permitted before arrow." },
161+
A_type_annotation_on_an_export_statement_is_only_allowed_in_an_ambient_external_module_declaration: { code: 1201, category: DiagnosticCategory.Error, key: "A type annotation on an export statement is only allowed in an ambient external module declaration." },
161162
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
162163
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
163164
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },

src/compiler/diagnosticMessages.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -617,12 +617,17 @@
617617
},
618618
"Unterminated Unicode escape sequence.": {
619619
"category": "Error",
620-
"code": 1199
620+
"code": 1199
621621
},
622622
"Line terminator not permitted before arrow.": {
623623
"category": "Error",
624624
"code": 1200
625625
},
626+
"A type annotation on an export statement is only allowed in an ambient external module declaration.": {
627+
"category": "Error",
628+
"code": 1201
629+
},
630+
626631
"Duplicate identifier '{0}'.": {
627632
"category": "Error",
628633
"code": 2300

src/compiler/parser.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ module ts {
283283
visitNode(cbNode, (<ImportOrExportSpecifier>node).name);
284284
case SyntaxKind.ExportAssignment:
285285
return visitNodes(cbNodes, node.modifiers) ||
286-
visitNode(cbNode, (<ExportAssignment>node).expression);
286+
visitNode(cbNode, (<ExportAssignment>node).expression) ||
287+
visitNode(cbNode, (<ExportAssignment>node).type);
287288
case SyntaxKind.TemplateExpression:
288289
return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNodes, (<TemplateExpression>node).templateSpans);
289290
case SyntaxKind.TemplateSpan:
@@ -4867,12 +4868,17 @@ module ts {
48674868
setModifiers(node, modifiers);
48684869
if (parseOptional(SyntaxKind.EqualsToken)) {
48694870
node.isExportEquals = true;
4871+
node.expression = parseAssignmentExpressionOrHigher();
48704872
}
48714873
else {
48724874
parseExpected(SyntaxKind.DefaultKeyword);
4875+
if (parseOptional(SyntaxKind.ColonToken)) {
4876+
node.type = parseType();
4877+
}
4878+
else {
4879+
node.expression = parseAssignmentExpressionOrHigher();
4880+
}
48734881
}
4874-
//node.exportName = parseIdentifier();
4875-
node.expression = parseAssignmentExpressionOrHigher();
48764882
parseSemicolon();
48774883
return finishNode(node);
48784884
}

src/compiler/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,8 @@ module ts {
944944

945945
export interface ExportAssignment extends Declaration, ModuleElement {
946946
isExportEquals?: boolean;
947-
expression: Expression;
947+
expression?: Expression;
948+
type?: TypeNode;
948949
}
949950

950951
export interface FileReference extends TextRange {

src/services/breakpoints.ts

+4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ module ts.BreakpointResolver {
173173
return textSpan(node, (<ThrowStatement>node).expression);
174174

175175
case SyntaxKind.ExportAssignment:
176+
if (!(<ExportAssignment>node).expression) {
177+
return undefined;
178+
}
179+
176180
// span on export = id
177181
return textSpan(node, (<ExportAssignment>node).expression);
178182

tests/baselines/reference/APISample_compile.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,8 @@ declare module "typescript" {
765765
type ExportSpecifier = ImportOrExportSpecifier;
766766
interface ExportAssignment extends Declaration, ModuleElement {
767767
isExportEquals?: boolean;
768-
expression: Expression;
768+
expression?: Expression;
769+
type?: TypeNode;
769770
}
770771
interface FileReference extends TextRange {
771772
fileName: string;

tests/baselines/reference/APISample_compile.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2333,9 +2333,13 @@ declare module "typescript" {
23332333
isExportEquals?: boolean;
23342334
>isExportEquals : boolean
23352335

2336-
expression: Expression;
2336+
expression?: Expression;
23372337
>expression : Expression
23382338
>Expression : Expression
2339+
2340+
type?: TypeNode;
2341+
>type : TypeNode
2342+
>TypeNode : TypeNode
23392343
}
23402344
interface FileReference extends TextRange {
23412345
>FileReference : FileReference

tests/baselines/reference/APISample_linter.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,8 @@ declare module "typescript" {
796796
type ExportSpecifier = ImportOrExportSpecifier;
797797
interface ExportAssignment extends Declaration, ModuleElement {
798798
isExportEquals?: boolean;
799-
expression: Expression;
799+
expression?: Expression;
800+
type?: TypeNode;
800801
}
801802
interface FileReference extends TextRange {
802803
fileName: string;

tests/baselines/reference/APISample_linter.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2479,9 +2479,13 @@ declare module "typescript" {
24792479
isExportEquals?: boolean;
24802480
>isExportEquals : boolean
24812481

2482-
expression: Expression;
2482+
expression?: Expression;
24832483
>expression : Expression
24842484
>Expression : Expression
2485+
2486+
type?: TypeNode;
2487+
>type : TypeNode
2488+
>TypeNode : TypeNode
24852489
}
24862490
interface FileReference extends TextRange {
24872491
>FileReference : FileReference

tests/baselines/reference/APISample_transform.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,8 @@ declare module "typescript" {
797797
type ExportSpecifier = ImportOrExportSpecifier;
798798
interface ExportAssignment extends Declaration, ModuleElement {
799799
isExportEquals?: boolean;
800-
expression: Expression;
800+
expression?: Expression;
801+
type?: TypeNode;
801802
}
802803
interface FileReference extends TextRange {
803804
fileName: string;

tests/baselines/reference/APISample_transform.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2429,9 +2429,13 @@ declare module "typescript" {
24292429
isExportEquals?: boolean;
24302430
>isExportEquals : boolean
24312431

2432-
expression: Expression;
2432+
expression?: Expression;
24332433
>expression : Expression
24342434
>Expression : Expression
2435+
2436+
type?: TypeNode;
2437+
>type : TypeNode
2438+
>TypeNode : TypeNode
24352439
}
24362440
interface FileReference extends TextRange {
24372441
>FileReference : FileReference

tests/baselines/reference/APISample_watcher.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,8 @@ declare module "typescript" {
834834
type ExportSpecifier = ImportOrExportSpecifier;
835835
interface ExportAssignment extends Declaration, ModuleElement {
836836
isExportEquals?: boolean;
837-
expression: Expression;
837+
expression?: Expression;
838+
type?: TypeNode;
838839
}
839840
interface FileReference extends TextRange {
840841
fileName: string;

tests/baselines/reference/APISample_watcher.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2602,9 +2602,13 @@ declare module "typescript" {
26022602
isExportEquals?: boolean;
26032603
>isExportEquals : boolean
26042604

2605-
expression: Expression;
2605+
expression?: Expression;
26062606
>expression : Expression
26072607
>Expression : Expression
2608+
2609+
type?: TypeNode;
2610+
>type : TypeNode
2611+
>TypeNode : TypeNode
26082612
}
26092613
interface FileReference extends TextRange {
26102614
>FileReference : FileReference
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests/cases/compiler/exportDefaultTypeAnnoation.ts(2,18): error TS1201: A type annotation on an export statement is only allowed in an ambient external module declaration.
2+
3+
4+
==== tests/cases/compiler/exportDefaultTypeAnnoation.ts (1 errors) ====
5+
6+
export default : number;
7+
~~~~~~
8+
!!! error TS1201: A type annotation on an export statement is only allowed in an ambient external module declaration.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//// [exportDefaultTypeAnnoation.ts]
2+
3+
export default : number;
4+
5+
//// [exportDefaultTypeAnnoation.js]
6+
module.exports = ;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [exportDefaultTypeAnnoation2.ts]
2+
3+
declare module "mod" {
4+
export default : number;
5+
}
6+
7+
//// [exportDefaultTypeAnnoation2.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== tests/cases/compiler/exportDefaultTypeAnnoation2.ts ===
2+
3+
No type information for this code.declare module "mod" {
4+
No type information for this code. export default : number;
5+
No type information for this code.}
6+
No type information for this code.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
tests/cases/compiler/reference1.ts(2,5): error TS2322: Type 'number' is not assignable to type 'string'.
2+
tests/cases/compiler/reference2.ts(2,5): error TS2322: Type 'number' is not assignable to type 'string'.
3+
4+
5+
==== tests/cases/compiler/mod.d.ts (0 errors) ====
6+
7+
declare module "mod" {
8+
export default : number;
9+
}
10+
11+
==== tests/cases/compiler/reference1.ts (1 errors) ====
12+
import d from "mod";
13+
var s: string = d; // Error
14+
~
15+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
16+
17+
==== tests/cases/compiler/reference2.ts (1 errors) ====
18+
import { default as d } from "mod";
19+
var s: string = d; // Error
20+
~
21+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/compiler/exportDefaultTypeAnnoation3.ts] ////
2+
3+
//// [mod.d.ts]
4+
5+
declare module "mod" {
6+
export default : number;
7+
}
8+
9+
//// [reference1.ts]
10+
import d from "mod";
11+
var s: string = d; // Error
12+
13+
//// [reference2.ts]
14+
import { default as d } from "mod";
15+
var s: string = d; // Error
16+
17+
//// [reference1.js]
18+
var d = require("mod");
19+
var s = d; // Error
20+
//// [reference2.js]
21+
var _mod = require("mod");
22+
var s = _mod.default; // Error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @target: es5
2+
// @module: commonjs
3+
4+
export default : number;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @target: es5
2+
// @module: commonjs
3+
4+
declare module "mod" {
5+
export default : number;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @target: es5
2+
// @module: commonjs
3+
4+
// @fileName: mod.d.ts
5+
declare module "mod" {
6+
export default : number;
7+
}
8+
9+
// @fileName: reference1.ts
10+
import d from "mod";
11+
var s: string = d; // Error
12+
13+
// @fileName: reference2.ts
14+
import { default as d } from "mod";
15+
var s: string = d; // Error

0 commit comments

Comments
 (0)