Skip to content

Commit a6a8a96

Browse files
committed
Support an optional type annotation on export default statement
1 parent 62cbe97 commit a6a8a96

24 files changed

+172
-22
lines changed

src/compiler/binder.ts

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

src/compiler/checker.ts

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

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

572572
function getTargetOfImportDeclaration(node: Declaration): Symbol {
@@ -622,7 +622,7 @@ module ts {
622622
if (!links.referenced) {
623623
links.referenced = true;
624624
var node = getDeclarationOfAliasSymbol(symbol);
625-
if (node.kind === SyntaxKind.ExportAssignment) {
625+
if (node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression) {
626626
// export default <symbol>
627627
checkExpressionCached((<ExportAssignment>node).expression);
628628
}
@@ -2061,7 +2061,16 @@ module ts {
20612061
}
20622062
// Handle export default expressions
20632063
if (declaration.kind === SyntaxKind.ExportAssignment) {
2064-
return links.type = checkExpression((<ExportAssignment>declaration).expression);
2064+
var exportAssignment = (<ExportAssignment>declaration);
2065+
if (exportAssignment.expression) {
2066+
return links.type = checkExpression(exportAssignment.expression);
2067+
}
2068+
else if (exportAssignment.type) {
2069+
return links.type = getTypeFromTypeNode(exportAssignment.type);
2070+
}
2071+
else {
2072+
return links.type = anyType;
2073+
}
20652074
}
20662075
// Handle variable, parameter or property
20672076
links.type = resolvingType;
@@ -10039,12 +10048,21 @@ module ts {
1003910048
if (!checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) {
1004010049
grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers);
1004110050
}
10042-
if (node.expression.kind === SyntaxKind.Identifier) {
10043-
markExportAsReferenced(node);
10051+
if (node.expression) {
10052+
if (node.expression.kind === SyntaxKind.Identifier) {
10053+
markExportAsReferenced(node);
10054+
}
10055+
else {
10056+
checkExpressionCached(node.expression);
10057+
}
1004410058
}
10045-
else {
10046-
checkExpressionCached(node.expression);
10059+
if (node.type) {
10060+
checkSourceElement(node.type);
10061+
if (!isInAmbientContext(node)) {
10062+
grammarErrorOnFirstToken(node.type, Diagnostics.Type_annotation_on_export_statements_are_only_allowed_in_ambient_module_declarations);
10063+
}
1004710064
}
10065+
1004810066
checkExternalModuleExports(container);
1004910067
}
1005010068

@@ -10880,7 +10898,7 @@ module ts {
1088010898
}
1088110899

1088210900
function generateNameForExportAssignment(node: ExportAssignment) {
10883-
if (node.expression.kind !== SyntaxKind.Identifier) {
10901+
if (node.expression && node.expression.kind !== SyntaxKind.Identifier) {
1088410902
assignGeneratedName(node, makeUniqueName("default"));
1088510903
}
1088610904
}

src/compiler/diagnosticInformationMap.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ module ts {
157157
Catch_clause_variable_cannot_have_an_initializer: { code: 1197, category: DiagnosticCategory.Error, key: "Catch clause variable cannot have an initializer." },
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." },
160+
Type_annotation_on_export_statements_are_only_allowed_in_ambient_module_declarations: { code: 1200, category: DiagnosticCategory.Error, key: "Type annotation on export statements are only allowed in ambient module declarations." },
160161
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
161162
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." },
162163
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,8 +617,13 @@
617617
},
618618
"Unterminated Unicode escape sequence.": {
619619
"category": "Error",
620-
"code": 1199
620+
"code": 1199
621621
},
622+
"Type annotation on export statements are only allowed in ambient module declarations.": {
623+
"category": "Error",
624+
"code": 1200
625+
},
626+
622627
"Duplicate identifier '{0}'.": {
623628
"category": "Error",
624629
"code": 2300

src/compiler/parser.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ module ts {
282282
visitNode(cbNode, (<ImportOrExportSpecifier>node).name);
283283
case SyntaxKind.ExportAssignment:
284284
return visitNodes(cbNodes, node.modifiers) ||
285-
visitNode(cbNode, (<ExportAssignment>node).expression);
285+
visitNode(cbNode, (<ExportAssignment>node).expression) ||
286+
visitNode(cbNode, (<ExportAssignment>node).type);
286287
case SyntaxKind.TemplateExpression:
287288
return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNodes, (<TemplateExpression>node).templateSpans);
288289
case SyntaxKind.TemplateSpan:
@@ -4862,12 +4863,17 @@ module ts {
48624863
setModifiers(node, modifiers);
48634864
if (parseOptional(SyntaxKind.EqualsToken)) {
48644865
node.isExportEquals = true;
4866+
node.expression = parseAssignmentExpressionOrHigher();
48654867
}
48664868
else {
48674869
parseExpected(SyntaxKind.DefaultKeyword);
4870+
if (parseOptional(SyntaxKind.ColonToken)) {
4871+
node.type = parseType();
4872+
}
4873+
else {
4874+
node.expression = parseAssignmentExpressionOrHigher();
4875+
}
48684876
}
4869-
//node.exportName = parseIdentifier();
4870-
node.expression = parseAssignmentExpressionOrHigher();
48714877
parseSemicolon();
48724878
return finishNode(node);
48734879
}

src/compiler/types.ts

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

941941
export interface ExportAssignment extends Declaration, ModuleElement {
942942
isExportEquals?: boolean;
943-
expression: Expression;
943+
expression?: Expression;
944+
type?: TypeNode;
944945
}
945946

946947
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
@@ -762,7 +762,8 @@ declare module "typescript" {
762762
type ExportSpecifier = ImportOrExportSpecifier;
763763
interface ExportAssignment extends Declaration, ModuleElement {
764764
isExportEquals?: boolean;
765-
expression: Expression;
765+
expression?: Expression;
766+
type?: TypeNode;
766767
}
767768
interface FileReference extends TextRange {
768769
fileName: string;

tests/baselines/reference/APISample_compile.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2324,9 +2324,13 @@ declare module "typescript" {
23242324
isExportEquals?: boolean;
23252325
>isExportEquals : boolean
23262326

2327-
expression: Expression;
2327+
expression?: Expression;
23282328
>expression : Expression
23292329
>Expression : Expression
2330+
2331+
type?: TypeNode;
2332+
>type : TypeNode
2333+
>TypeNode : TypeNode
23302334
}
23312335
interface FileReference extends TextRange {
23322336
>FileReference : FileReference

tests/baselines/reference/APISample_linter.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,8 @@ declare module "typescript" {
793793
type ExportSpecifier = ImportOrExportSpecifier;
794794
interface ExportAssignment extends Declaration, ModuleElement {
795795
isExportEquals?: boolean;
796-
expression: Expression;
796+
expression?: Expression;
797+
type?: TypeNode;
797798
}
798799
interface FileReference extends TextRange {
799800
fileName: string;

tests/baselines/reference/APISample_linter.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2470,9 +2470,13 @@ declare module "typescript" {
24702470
isExportEquals?: boolean;
24712471
>isExportEquals : boolean
24722472

2473-
expression: Expression;
2473+
expression?: Expression;
24742474
>expression : Expression
24752475
>Expression : Expression
2476+
2477+
type?: TypeNode;
2478+
>type : TypeNode
2479+
>TypeNode : TypeNode
24762480
}
24772481
interface FileReference extends TextRange {
24782482
>FileReference : FileReference

tests/baselines/reference/APISample_transform.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,8 @@ declare module "typescript" {
794794
type ExportSpecifier = ImportOrExportSpecifier;
795795
interface ExportAssignment extends Declaration, ModuleElement {
796796
isExportEquals?: boolean;
797-
expression: Expression;
797+
expression?: Expression;
798+
type?: TypeNode;
798799
}
799800
interface FileReference extends TextRange {
800801
fileName: string;

tests/baselines/reference/APISample_transform.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2420,9 +2420,13 @@ declare module "typescript" {
24202420
isExportEquals?: boolean;
24212421
>isExportEquals : boolean
24222422

2423-
expression: Expression;
2423+
expression?: Expression;
24242424
>expression : Expression
24252425
>Expression : Expression
2426+
2427+
type?: TypeNode;
2428+
>type : TypeNode
2429+
>TypeNode : TypeNode
24262430
}
24272431
interface FileReference extends TextRange {
24282432
>FileReference : FileReference

tests/baselines/reference/APISample_watcher.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,8 @@ declare module "typescript" {
831831
type ExportSpecifier = ImportOrExportSpecifier;
832832
interface ExportAssignment extends Declaration, ModuleElement {
833833
isExportEquals?: boolean;
834-
expression: Expression;
834+
expression?: Expression;
835+
type?: TypeNode;
835836
}
836837
interface FileReference extends TextRange {
837838
fileName: string;

tests/baselines/reference/APISample_watcher.types

+5-1
Original file line numberDiff line numberDiff line change
@@ -2593,9 +2593,13 @@ declare module "typescript" {
25932593
isExportEquals?: boolean;
25942594
>isExportEquals : boolean
25952595

2596-
expression: Expression;
2596+
expression?: Expression;
25972597
>expression : Expression
25982598
>Expression : Expression
2599+
2600+
type?: TypeNode;
2601+
>type : TypeNode
2602+
>TypeNode : TypeNode
25992603
}
26002604
interface FileReference extends TextRange {
26012605
>FileReference : FileReference
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests/cases/compiler/exportDefaultTypeAnnoation.ts(2,18): error TS1200: Type annotation on export statements are only allowed in ambient module declarations.
2+
3+
4+
==== tests/cases/compiler/exportDefaultTypeAnnoation.ts (1 errors) ====
5+
6+
export default : number;
7+
~~~~~~
8+
!!! error TS1200: Type annotation on export statements are only allowed in ambient module declarations.
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)