diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 7c1e4c57a4c..f951fe49269 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -505,7 +505,7 @@ module ts { bindChildren(node, 0, /*isBlockScopeContainer*/ false); break; case SyntaxKind.ExportAssignment: - if ((node).expression.kind === SyntaxKind.Identifier) { + if ((node).expression && (node).expression.kind === SyntaxKind.Identifier) { // An export default clause with an identifier exports all meanings of that identifier declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4816bac9fcb..eb033794aee 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -567,7 +567,7 @@ module ts { } function getTargetOfExportAssignment(node: ExportAssignment): Symbol { - return resolveEntityName(node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); + return node.expression && resolveEntityName(node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace); } function getTargetOfImportDeclaration(node: Declaration): Symbol { @@ -623,7 +623,7 @@ module ts { if (!links.referenced) { links.referenced = true; let node = getDeclarationOfAliasSymbol(symbol); - if (node.kind === SyntaxKind.ExportAssignment) { + if (node.kind === SyntaxKind.ExportAssignment && (node).expression) { // export default checkExpressionCached((node).expression); } @@ -2073,7 +2073,16 @@ module ts { } // Handle export default expressions if (declaration.kind === SyntaxKind.ExportAssignment) { - return links.type = checkExpression((declaration).expression); + var exportAssignment = declaration; + if (exportAssignment.expression) { + return links.type = checkExpression(exportAssignment.expression); + } + else if (exportAssignment.type) { + return links.type = getTypeFromTypeNode(exportAssignment.type); + } + else { + return links.type = anyType; + } } // Handle variable, parameter or property links.type = resolvingType; @@ -10075,12 +10084,21 @@ module ts { if (!checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers); } - if (node.expression.kind === SyntaxKind.Identifier) { - markExportAsReferenced(node); + if (node.expression) { + if (node.expression.kind === SyntaxKind.Identifier) { + markExportAsReferenced(node); + } + else { + checkExpressionCached(node.expression); + } } - else { - checkExpressionCached(node.expression); + if (node.type) { + checkSourceElement(node.type); + if (!isInAmbientContext(node)) { + grammarErrorOnFirstToken(node.type, Diagnostics.A_type_annotation_on_an_export_statement_is_only_allowed_in_an_ambient_external_module_declaration); + } } + checkExternalModuleExports(container); } @@ -10914,7 +10932,7 @@ module ts { } function generateNameForExportAssignment(node: ExportAssignment) { - if (node.expression.kind !== SyntaxKind.Identifier) { + if (node.expression && node.expression.kind !== SyntaxKind.Identifier) { assignGeneratedName(node, makeUniqueName("default")); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 556df1565b0..622b28d5f18 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -158,6 +158,7 @@ module ts { 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." }, Unterminated_Unicode_escape_sequence: { code: 1199, category: DiagnosticCategory.Error, key: "Unterminated Unicode escape sequence." }, Line_terminator_not_permitted_before_arrow: { code: 1200, category: DiagnosticCategory.Error, key: "Line terminator not permitted before arrow." }, + 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." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, 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." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0c00d8c974c..410cce54d17 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -617,12 +617,17 @@ }, "Unterminated Unicode escape sequence.": { "category": "Error", - "code": 1199 + "code": 1199 }, "Line terminator not permitted before arrow.": { "category": "Error", "code": 1200 }, + "A type annotation on an export statement is only allowed in an ambient external module declaration.": { + "category": "Error", + "code": 1201 + }, + "Duplicate identifier '{0}'.": { "category": "Error", "code": 2300 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 27f550778c1..6aed05193e8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -283,7 +283,8 @@ module ts { visitNode(cbNode, (node).name); case SyntaxKind.ExportAssignment: return visitNodes(cbNodes, node.modifiers) || - visitNode(cbNode, (node).expression); + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).type); case SyntaxKind.TemplateExpression: return visitNode(cbNode, (node).head) || visitNodes(cbNodes, (node).templateSpans); case SyntaxKind.TemplateSpan: @@ -4867,12 +4868,17 @@ module ts { setModifiers(node, modifiers); if (parseOptional(SyntaxKind.EqualsToken)) { node.isExportEquals = true; + node.expression = parseAssignmentExpressionOrHigher(); } else { parseExpected(SyntaxKind.DefaultKeyword); + if (parseOptional(SyntaxKind.ColonToken)) { + node.type = parseType(); + } + else { + node.expression = parseAssignmentExpressionOrHigher(); + } } - //node.exportName = parseIdentifier(); - node.expression = parseAssignmentExpressionOrHigher(); parseSemicolon(); return finishNode(node); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 25a8ce75245..91ad490e50f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -944,7 +944,8 @@ module ts { export interface ExportAssignment extends Declaration, ModuleElement { isExportEquals?: boolean; - expression: Expression; + expression?: Expression; + type?: TypeNode; } export interface FileReference extends TextRange { diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index c56ea72cd66..395141cc4cc 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -173,6 +173,10 @@ module ts.BreakpointResolver { return textSpan(node, (node).expression); case SyntaxKind.ExportAssignment: + if (!(node).expression) { + return undefined; + } + // span on export = id return textSpan(node, (node).expression); diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 6244dc73951..b03081d721d 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -765,7 +765,8 @@ declare module "typescript" { type ExportSpecifier = ImportOrExportSpecifier; interface ExportAssignment extends Declaration, ModuleElement { isExportEquals?: boolean; - expression: Expression; + expression?: Expression; + type?: TypeNode; } interface FileReference extends TextRange { fileName: string; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 43e88c27e41..e14cd96d2bc 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -2333,9 +2333,13 @@ declare module "typescript" { isExportEquals?: boolean; >isExportEquals : boolean - expression: Expression; + expression?: Expression; >expression : Expression >Expression : Expression + + type?: TypeNode; +>type : TypeNode +>TypeNode : TypeNode } interface FileReference extends TextRange { >FileReference : FileReference diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index fd4649f614d..313d03f14d0 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -796,7 +796,8 @@ declare module "typescript" { type ExportSpecifier = ImportOrExportSpecifier; interface ExportAssignment extends Declaration, ModuleElement { isExportEquals?: boolean; - expression: Expression; + expression?: Expression; + type?: TypeNode; } interface FileReference extends TextRange { fileName: string; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 984b59ca7ee..538cab1382a 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -2479,9 +2479,13 @@ declare module "typescript" { isExportEquals?: boolean; >isExportEquals : boolean - expression: Expression; + expression?: Expression; >expression : Expression >Expression : Expression + + type?: TypeNode; +>type : TypeNode +>TypeNode : TypeNode } interface FileReference extends TextRange { >FileReference : FileReference diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 4222e1b2d98..e34e271c6a1 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -797,7 +797,8 @@ declare module "typescript" { type ExportSpecifier = ImportOrExportSpecifier; interface ExportAssignment extends Declaration, ModuleElement { isExportEquals?: boolean; - expression: Expression; + expression?: Expression; + type?: TypeNode; } interface FileReference extends TextRange { fileName: string; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index bea3f1e7231..663dc59c843 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -2429,9 +2429,13 @@ declare module "typescript" { isExportEquals?: boolean; >isExportEquals : boolean - expression: Expression; + expression?: Expression; >expression : Expression >Expression : Expression + + type?: TypeNode; +>type : TypeNode +>TypeNode : TypeNode } interface FileReference extends TextRange { >FileReference : FileReference diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 0928c2cf139..ff762af1d9e 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -834,7 +834,8 @@ declare module "typescript" { type ExportSpecifier = ImportOrExportSpecifier; interface ExportAssignment extends Declaration, ModuleElement { isExportEquals?: boolean; - expression: Expression; + expression?: Expression; + type?: TypeNode; } interface FileReference extends TextRange { fileName: string; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 4498a5538e4..8ea691d2d0d 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -2602,9 +2602,13 @@ declare module "typescript" { isExportEquals?: boolean; >isExportEquals : boolean - expression: Expression; + expression?: Expression; >expression : Expression >Expression : Expression + + type?: TypeNode; +>type : TypeNode +>TypeNode : TypeNode } interface FileReference extends TextRange { >FileReference : FileReference diff --git a/tests/baselines/reference/exportDefaultTypeAnnoation.errors.txt b/tests/baselines/reference/exportDefaultTypeAnnoation.errors.txt new file mode 100644 index 00000000000..71ff4261ffe --- /dev/null +++ b/tests/baselines/reference/exportDefaultTypeAnnoation.errors.txt @@ -0,0 +1,8 @@ +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. + + +==== tests/cases/compiler/exportDefaultTypeAnnoation.ts (1 errors) ==== + + export default : number; + ~~~~~~ +!!! error TS1201: A type annotation on an export statement is only allowed in an ambient external module declaration. \ No newline at end of file diff --git a/tests/baselines/reference/exportDefaultTypeAnnoation.js b/tests/baselines/reference/exportDefaultTypeAnnoation.js new file mode 100644 index 00000000000..8adf31a5f18 --- /dev/null +++ b/tests/baselines/reference/exportDefaultTypeAnnoation.js @@ -0,0 +1,6 @@ +//// [exportDefaultTypeAnnoation.ts] + +export default : number; + +//// [exportDefaultTypeAnnoation.js] +module.exports = ; diff --git a/tests/baselines/reference/exportDefaultTypeAnnoation2.js b/tests/baselines/reference/exportDefaultTypeAnnoation2.js new file mode 100644 index 00000000000..2c918954702 --- /dev/null +++ b/tests/baselines/reference/exportDefaultTypeAnnoation2.js @@ -0,0 +1,7 @@ +//// [exportDefaultTypeAnnoation2.ts] + +declare module "mod" { + export default : number; +} + +//// [exportDefaultTypeAnnoation2.js] diff --git a/tests/baselines/reference/exportDefaultTypeAnnoation2.types b/tests/baselines/reference/exportDefaultTypeAnnoation2.types new file mode 100644 index 00000000000..53ca78586cc --- /dev/null +++ b/tests/baselines/reference/exportDefaultTypeAnnoation2.types @@ -0,0 +1,6 @@ +=== tests/cases/compiler/exportDefaultTypeAnnoation2.ts === + +No type information for this code.declare module "mod" { +No type information for this code. export default : number; +No type information for this code.} +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/exportDefaultTypeAnnoation3.errors.txt b/tests/baselines/reference/exportDefaultTypeAnnoation3.errors.txt new file mode 100644 index 00000000000..326713e059e --- /dev/null +++ b/tests/baselines/reference/exportDefaultTypeAnnoation3.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/reference1.ts(2,5): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/reference2.ts(2,5): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== tests/cases/compiler/mod.d.ts (0 errors) ==== + + declare module "mod" { + export default : number; + } + +==== tests/cases/compiler/reference1.ts (1 errors) ==== + import d from "mod"; + var s: string = d; // Error + ~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + +==== tests/cases/compiler/reference2.ts (1 errors) ==== + import { default as d } from "mod"; + var s: string = d; // Error + ~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. \ No newline at end of file diff --git a/tests/baselines/reference/exportDefaultTypeAnnoation3.js b/tests/baselines/reference/exportDefaultTypeAnnoation3.js new file mode 100644 index 00000000000..069c8385e77 --- /dev/null +++ b/tests/baselines/reference/exportDefaultTypeAnnoation3.js @@ -0,0 +1,22 @@ +//// [tests/cases/compiler/exportDefaultTypeAnnoation3.ts] //// + +//// [mod.d.ts] + +declare module "mod" { + export default : number; +} + +//// [reference1.ts] +import d from "mod"; +var s: string = d; // Error + +//// [reference2.ts] +import { default as d } from "mod"; +var s: string = d; // Error + +//// [reference1.js] +var d = require("mod"); +var s = d; // Error +//// [reference2.js] +var _mod = require("mod"); +var s = _mod.default; // Error diff --git a/tests/cases/compiler/exportDefaultTypeAnnoation.ts b/tests/cases/compiler/exportDefaultTypeAnnoation.ts new file mode 100644 index 00000000000..d7fd24d5be3 --- /dev/null +++ b/tests/cases/compiler/exportDefaultTypeAnnoation.ts @@ -0,0 +1,4 @@ +// @target: es5 +// @module: commonjs + +export default : number; \ No newline at end of file diff --git a/tests/cases/compiler/exportDefaultTypeAnnoation2.ts b/tests/cases/compiler/exportDefaultTypeAnnoation2.ts new file mode 100644 index 00000000000..ddb317bd8fc --- /dev/null +++ b/tests/cases/compiler/exportDefaultTypeAnnoation2.ts @@ -0,0 +1,6 @@ +// @target: es5 +// @module: commonjs + +declare module "mod" { + export default : number; +} \ No newline at end of file diff --git a/tests/cases/compiler/exportDefaultTypeAnnoation3.ts b/tests/cases/compiler/exportDefaultTypeAnnoation3.ts new file mode 100644 index 00000000000..88a45de2d32 --- /dev/null +++ b/tests/cases/compiler/exportDefaultTypeAnnoation3.ts @@ -0,0 +1,15 @@ +// @target: es5 +// @module: commonjs + +// @fileName: mod.d.ts +declare module "mod" { + export default : number; +} + +// @fileName: reference1.ts +import d from "mod"; +var s: string = d; // Error + +// @fileName: reference2.ts +import { default as d } from "mod"; +var s: string = d; // Error \ No newline at end of file