From e36096544777feef142602a72dd22fb4f01b7449 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 26 Feb 2020 16:36:00 -0800 Subject: [PATCH 1/4] Recognize `export type *` syntax, but disallow it --- src/compiler/checker.ts | 38 ++++++++++++---- src/compiler/diagnosticMessages.json | 4 ++ src/compiler/utilities.ts | 5 +++ src/compiler/utilitiesPublic.ts | 6 ++- .../reference/exportNamespace4.errors.txt | 33 ++++++++++++++ tests/baselines/reference/exportNamespace4.js | 43 +++++++++++++++++++ .../reference/exportNamespace4.symbols | 27 ++++++++++++ .../reference/exportNamespace4.types | 27 ++++++++++++ .../typeOnly/exportNamespace4.ts | 16 +++++++ 9 files changed, 188 insertions(+), 11 deletions(-) create mode 100644 tests/baselines/reference/exportNamespace4.errors.txt create mode 100644 tests/baselines/reference/exportNamespace4.js create mode 100644 tests/baselines/reference/exportNamespace4.symbols create mode 100644 tests/baselines/reference/exportNamespace4.types create mode 100644 tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 34e8a6336ae3c..51af91142446c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1936,10 +1936,11 @@ namespace ts { if (!isValidTypeOnlyAliasUseSite(useSite)) { const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(symbol); if (typeOnlyDeclaration) { - const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + const isExport = typeOnlyDeclarationIsExport(typeOnlyDeclaration); + const message = isExport ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type; - const relatedMessage = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + const relatedMessage = isExport ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here; const unescapedName = unescapeLeadingUnderscores(name); @@ -2286,15 +2287,19 @@ namespace ts { function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) { if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false)) { const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfNode(node))!; - const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + const isExport = typeOnlyDeclarationIsExport(typeOnlyDeclaration); + const message = isExport ? Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_exported_using_export_type : Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_imported_using_import_type; - const relatedMessage = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + const relatedMessage = isExport ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here; - // Non-null assertion is safe because the optionality comes from ImportClause, - // but if an ImportClause was the typeOnlyDeclaration, it had to have a `name`. - const name = unescapeLeadingUnderscores(typeOnlyDeclaration.name!.escapedText); + + // Non-null assertion is safe because `markSymbolOfAliasDeclarationIfTypeOnly` cannot return true + // for an ImportEqualsDeclaration without also being passed a defined symbol. + // `typeOnlyDeclaration.name` will be an Identifier for all valid cases, but may be undefined for + // invalid `export type * ...` syntax. + const name = unescapeLeadingUnderscores(tryCast(typeOnlyDeclaration.name, isIdentifier)?.escapedText ?? resolved!.escapedName); addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)); } } @@ -2452,7 +2457,12 @@ namespace ts { const name = (specifier.propertyName ?? specifier.name).escapedText; const exportSymbol = getExportsOfSymbol(symbol).get(name); const resolved = resolveSymbol(exportSymbol, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false); + if (!markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false)) { + if (resolved && symbol.exports && !symbol.exports.has(name)) { + // `resolved` must have come from a namespace export, which could be `export type *` + markSymbolOfAliasDeclarationIfTypeOnly(specifier, symbol.exports.get(InternalSymbolName.ExportStar), /*finalTarget*/ undefined, /*overwriteEmpty*/ true); + } + } return resolved; } } @@ -2725,7 +2735,7 @@ namespace ts { } /** Indicates that a symbol directly or indirectly resolves to a type-only import or export. */ - function getTypeOnlyAliasDeclaration(symbol: Symbol): TypeOnlyCompatibleAliasDeclaration | undefined { + function getTypeOnlyAliasDeclaration(symbol: Symbol): TypeOnlyCompatibleAliasDeclaration | NamespaceExport | ExportDeclaration | undefined { if (!(symbol.flags & SymbolFlags.Alias)) { return undefined; } @@ -3262,6 +3272,7 @@ namespace ts { const lookupTable = createMap() as ExportCollisionTrackerTable; for (const node of exportStars.declarations) { const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); + markSymbolOfAliasDeclarationIfTypeOnly(node, resolvedModule, /*finalTarget*/ undefined, /*overwriteEmpty*/ false); const exportedSymbols = visit(resolvedModule); extendExportSymbols( nestedSymbols, @@ -33537,6 +33548,7 @@ namespace ts { checkExternalEmitHelpers(node, ExternalEmitHelpers.CreateBinding); } + checkGrammarExportDeclaration(node); if (!node.moduleSpecifier || checkExternalImportOrExportDeclaration(node)) { if (node.exportClause) { // export { x, y } @@ -33569,6 +33581,14 @@ namespace ts { } } + function checkGrammarExportDeclaration(node: ExportDeclaration): boolean { + const isTypeOnlyExportStar = node.isTypeOnly && node.exportClause?.kind !== SyntaxKind.NamedExports; + if (isTypeOnlyExportStar) { + grammarErrorOnNode(node, Diagnostics.Only_named_exports_may_use_export_type); + } + return !isTypeOnlyExportStar; + } + function checkGrammarModuleElementContext(node: Statement, errorMessage: DiagnosticMessage): boolean { const isInAppropriateContext = node.parent.kind === SyntaxKind.SourceFile || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.ModuleDeclaration; if (!isInAppropriateContext) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4ee407ce1c1e9..b58c0cd92783c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1143,6 +1143,10 @@ "category": "Error", "code": 1382 }, + "Only named exports may use 'export type'.": { + "category": "Error", + "code": 1383 + }, "The types of '{0}' are incompatible between these types.": { "category": "Error", diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7badd3af99e39..fc72453565194 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6215,6 +6215,11 @@ namespace ts { || !isExpressionNode(useSite); } + export function typeOnlyDeclarationIsExport(typeOnlyDeclaration: Node) { + const kind = typeOnlyDeclaration.kind; + return kind === SyntaxKind.ExportSpecifier || kind === SyntaxKind.NamespaceExport || kind === SyntaxKind.ExportDeclaration; + } + function isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node: Node) { while (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) { node = node.parent; diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 052144fdc001f..8fd8426980458 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1727,9 +1727,11 @@ namespace ts { case SyntaxKind.ExportSpecifier: return (node as ImportOrExportSpecifier).parent.parent.isTypeOnly; case SyntaxKind.NamespaceImport: - return (node as NamespaceImport).parent.isTypeOnly; + case SyntaxKind.NamespaceExport: + return (node as NamespaceImport | NamespaceExport).parent.isTypeOnly; case SyntaxKind.ImportClause: - return (node as ImportClause).isTypeOnly; + case SyntaxKind.ExportDeclaration: + return (node as ImportClause | ExportDeclaration).isTypeOnly; default: return false; } diff --git a/tests/baselines/reference/exportNamespace4.errors.txt b/tests/baselines/reference/exportNamespace4.errors.txt new file mode 100644 index 0000000000000..36c1a5d24eb86 --- /dev/null +++ b/tests/baselines/reference/exportNamespace4.errors.txt @@ -0,0 +1,33 @@ +tests/cases/conformance/externalModules/typeOnly/b.ts(1,1): error TS1383: Only named exports may use 'export type'. +tests/cases/conformance/externalModules/typeOnly/c.ts(1,1): error TS1383: Only named exports may use 'export type'. +tests/cases/conformance/externalModules/typeOnly/d.ts(2,1): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'. +tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'. + + +==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ==== + export class A {} + +==== tests/cases/conformance/externalModules/typeOnly/b.ts (1 errors) ==== + export type * from './a'; + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1383: Only named exports may use 'export type'. + +==== tests/cases/conformance/externalModules/typeOnly/c.ts (1 errors) ==== + export type * as ns from './a'; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1383: Only named exports may use 'export type'. + +==== tests/cases/conformance/externalModules/typeOnly/d.ts (1 errors) ==== + import { A } from './b'; + A; // Error + ~ +!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'. +!!! related TS1377 tests/cases/conformance/externalModules/typeOnly/b.ts:1:1: 'A' was exported here. + +==== tests/cases/conformance/externalModules/typeOnly/e.ts (1 errors) ==== + import { ns } from './c'; + ns.A; // Error + ~~ +!!! error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'. +!!! related TS1377 tests/cases/conformance/externalModules/typeOnly/c.ts:1:13: 'ns' was exported here. + \ No newline at end of file diff --git a/tests/baselines/reference/exportNamespace4.js b/tests/baselines/reference/exportNamespace4.js new file mode 100644 index 0000000000000..e575549156ab9 --- /dev/null +++ b/tests/baselines/reference/exportNamespace4.js @@ -0,0 +1,43 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts] //// + +//// [a.ts] +export class A {} + +//// [b.ts] +export type * from './a'; + +//// [c.ts] +export type * as ns from './a'; + +//// [d.ts] +import { A } from './b'; +A; // Error + +//// [e.ts] +import { ns } from './c'; +ns.A; // Error + + +//// [a.js] +"use strict"; +exports.__esModule = true; +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +exports.A = A; +//// [b.js] +"use strict"; +exports.__esModule = true; +//// [c.js] +"use strict"; +exports.__esModule = true; +//// [d.js] +"use strict"; +exports.__esModule = true; +A; // Error +//// [e.js] +"use strict"; +exports.__esModule = true; +ns.A; // Error diff --git a/tests/baselines/reference/exportNamespace4.symbols b/tests/baselines/reference/exportNamespace4.symbols new file mode 100644 index 0000000000000..5ba8df1390e5a --- /dev/null +++ b/tests/baselines/reference/exportNamespace4.symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/externalModules/typeOnly/a.ts === +export class A {} +>A : Symbol(A, Decl(a.ts, 0, 0)) + +=== tests/cases/conformance/externalModules/typeOnly/b.ts === +export type * from './a'; +No type information for this code. +No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/c.ts === +export type * as ns from './a'; +>ns : Symbol(ns, Decl(c.ts, 0, 11)) + +=== tests/cases/conformance/externalModules/typeOnly/d.ts === +import { A } from './b'; +>A : Symbol(A, Decl(d.ts, 0, 8)) + +A; // Error +>A : Symbol(A, Decl(d.ts, 0, 8)) + +=== tests/cases/conformance/externalModules/typeOnly/e.ts === +import { ns } from './c'; +>ns : Symbol(ns, Decl(e.ts, 0, 8)) + +ns.A; // Error +>ns.A : Symbol(ns.A, Decl(a.ts, 0, 0)) +>ns : Symbol(ns, Decl(e.ts, 0, 8)) +>A : Symbol(ns.A, Decl(a.ts, 0, 0)) + diff --git a/tests/baselines/reference/exportNamespace4.types b/tests/baselines/reference/exportNamespace4.types new file mode 100644 index 0000000000000..2e3ead71d0fc3 --- /dev/null +++ b/tests/baselines/reference/exportNamespace4.types @@ -0,0 +1,27 @@ +=== tests/cases/conformance/externalModules/typeOnly/a.ts === +export class A {} +>A : A + +=== tests/cases/conformance/externalModules/typeOnly/b.ts === +export type * from './a'; +No type information for this code. +No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/c.ts === +export type * as ns from './a'; +>ns : typeof ns + +=== tests/cases/conformance/externalModules/typeOnly/d.ts === +import { A } from './b'; +>A : typeof A + +A; // Error +>A : typeof A + +=== tests/cases/conformance/externalModules/typeOnly/e.ts === +import { ns } from './c'; +>ns : typeof ns + +ns.A; // Error +>ns.A : typeof ns.A +>ns : typeof ns +>A : typeof ns.A + diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts new file mode 100644 index 0000000000000..5a6b7f6835c5c --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts @@ -0,0 +1,16 @@ +// @Filename: a.ts +export class A {} + +// @Filename: b.ts +export type * from './a'; + +// @Filename: c.ts +export type * as ns from './a'; + +// @Filename: d.ts +import { A } from './b'; +A; // Error + +// @Filename: e.ts +import { ns } from './c'; +ns.A; // Error From 7615d29b00d80d03af934689918c8b3c6f3d2547 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 26 Feb 2020 16:39:33 -0800 Subject: [PATCH 2/4] Add more comments to test --- tests/baselines/reference/exportNamespace4.errors.txt | 4 ++-- tests/baselines/reference/exportNamespace4.js | 4 ++-- tests/baselines/reference/exportNamespace4.symbols | 4 ++-- tests/baselines/reference/exportNamespace4.types | 4 ++-- .../conformance/externalModules/typeOnly/exportNamespace4.ts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/baselines/reference/exportNamespace4.errors.txt b/tests/baselines/reference/exportNamespace4.errors.txt index 36c1a5d24eb86..706d5b14d698b 100644 --- a/tests/baselines/reference/exportNamespace4.errors.txt +++ b/tests/baselines/reference/exportNamespace4.errors.txt @@ -8,12 +8,12 @@ tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1362: 'ns' c export class A {} ==== tests/cases/conformance/externalModules/typeOnly/b.ts (1 errors) ==== - export type * from './a'; + export type * from './a'; // Grammar error ~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS1383: Only named exports may use 'export type'. ==== tests/cases/conformance/externalModules/typeOnly/c.ts (1 errors) ==== - export type * as ns from './a'; + export type * as ns from './a'; // Grammar error ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS1383: Only named exports may use 'export type'. diff --git a/tests/baselines/reference/exportNamespace4.js b/tests/baselines/reference/exportNamespace4.js index e575549156ab9..d17adcc51176a 100644 --- a/tests/baselines/reference/exportNamespace4.js +++ b/tests/baselines/reference/exportNamespace4.js @@ -4,10 +4,10 @@ export class A {} //// [b.ts] -export type * from './a'; +export type * from './a'; // Grammar error //// [c.ts] -export type * as ns from './a'; +export type * as ns from './a'; // Grammar error //// [d.ts] import { A } from './b'; diff --git a/tests/baselines/reference/exportNamespace4.symbols b/tests/baselines/reference/exportNamespace4.symbols index 5ba8df1390e5a..c93887db8aa5a 100644 --- a/tests/baselines/reference/exportNamespace4.symbols +++ b/tests/baselines/reference/exportNamespace4.symbols @@ -3,10 +3,10 @@ export class A {} >A : Symbol(A, Decl(a.ts, 0, 0)) === tests/cases/conformance/externalModules/typeOnly/b.ts === -export type * from './a'; +export type * from './a'; // Grammar error No type information for this code. No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/c.ts === -export type * as ns from './a'; +export type * as ns from './a'; // Grammar error >ns : Symbol(ns, Decl(c.ts, 0, 11)) === tests/cases/conformance/externalModules/typeOnly/d.ts === diff --git a/tests/baselines/reference/exportNamespace4.types b/tests/baselines/reference/exportNamespace4.types index 2e3ead71d0fc3..897dd4cc3c796 100644 --- a/tests/baselines/reference/exportNamespace4.types +++ b/tests/baselines/reference/exportNamespace4.types @@ -3,10 +3,10 @@ export class A {} >A : A === tests/cases/conformance/externalModules/typeOnly/b.ts === -export type * from './a'; +export type * from './a'; // Grammar error No type information for this code. No type information for this code.=== tests/cases/conformance/externalModules/typeOnly/c.ts === -export type * as ns from './a'; +export type * as ns from './a'; // Grammar error >ns : typeof ns === tests/cases/conformance/externalModules/typeOnly/d.ts === diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts index 5a6b7f6835c5c..3f708ce0d54e2 100644 --- a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts +++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts @@ -2,10 +2,10 @@ export class A {} // @Filename: b.ts -export type * from './a'; +export type * from './a'; // Grammar error // @Filename: c.ts -export type * as ns from './a'; +export type * as ns from './a'; // Grammar error // @Filename: d.ts import { A } from './b'; From 81f62824dda055f52a38fd254112ae6b54128d31 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 27 Feb 2020 11:32:07 -0800 Subject: [PATCH 3/4] Revert recognizing invalid forms as type-only --- src/compiler/checker.ts | 8 +------- src/compiler/utilitiesPublic.ts | 6 ++---- .../reference/exportNamespace4.errors.txt | 16 ++++------------ tests/baselines/reference/exportNamespace4.js | 10 ++++++---- .../baselines/reference/exportNamespace4.symbols | 4 ++-- tests/baselines/reference/exportNamespace4.types | 4 ++-- .../externalModules/typeOnly/exportNamespace4.ts | 4 ++-- 7 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 51af91142446c..514b5af7d2fea 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2457,12 +2457,7 @@ namespace ts { const name = (specifier.propertyName ?? specifier.name).escapedText; const exportSymbol = getExportsOfSymbol(symbol).get(name); const resolved = resolveSymbol(exportSymbol, dontResolveAlias); - if (!markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false)) { - if (resolved && symbol.exports && !symbol.exports.has(name)) { - // `resolved` must have come from a namespace export, which could be `export type *` - markSymbolOfAliasDeclarationIfTypeOnly(specifier, symbol.exports.get(InternalSymbolName.ExportStar), /*finalTarget*/ undefined, /*overwriteEmpty*/ true); - } - } + markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false); return resolved; } } @@ -3272,7 +3267,6 @@ namespace ts { const lookupTable = createMap() as ExportCollisionTrackerTable; for (const node of exportStars.declarations) { const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); - markSymbolOfAliasDeclarationIfTypeOnly(node, resolvedModule, /*finalTarget*/ undefined, /*overwriteEmpty*/ false); const exportedSymbols = visit(resolvedModule); extendExportSymbols( nestedSymbols, diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 8fd8426980458..052144fdc001f 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1727,11 +1727,9 @@ namespace ts { case SyntaxKind.ExportSpecifier: return (node as ImportOrExportSpecifier).parent.parent.isTypeOnly; case SyntaxKind.NamespaceImport: - case SyntaxKind.NamespaceExport: - return (node as NamespaceImport | NamespaceExport).parent.isTypeOnly; + return (node as NamespaceImport).parent.isTypeOnly; case SyntaxKind.ImportClause: - case SyntaxKind.ExportDeclaration: - return (node as ImportClause | ExportDeclaration).isTypeOnly; + return (node as ImportClause).isTypeOnly; default: return false; } diff --git a/tests/baselines/reference/exportNamespace4.errors.txt b/tests/baselines/reference/exportNamespace4.errors.txt index 706d5b14d698b..30b849456e67f 100644 --- a/tests/baselines/reference/exportNamespace4.errors.txt +++ b/tests/baselines/reference/exportNamespace4.errors.txt @@ -1,7 +1,5 @@ tests/cases/conformance/externalModules/typeOnly/b.ts(1,1): error TS1383: Only named exports may use 'export type'. tests/cases/conformance/externalModules/typeOnly/c.ts(1,1): error TS1383: Only named exports may use 'export type'. -tests/cases/conformance/externalModules/typeOnly/d.ts(2,1): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'. -tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'. ==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ==== @@ -17,17 +15,11 @@ tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1362: 'ns' c ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS1383: Only named exports may use 'export type'. -==== tests/cases/conformance/externalModules/typeOnly/d.ts (1 errors) ==== +==== tests/cases/conformance/externalModules/typeOnly/d.ts (0 errors) ==== import { A } from './b'; - A; // Error - ~ -!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'. -!!! related TS1377 tests/cases/conformance/externalModules/typeOnly/b.ts:1:1: 'A' was exported here. + A; -==== tests/cases/conformance/externalModules/typeOnly/e.ts (1 errors) ==== +==== tests/cases/conformance/externalModules/typeOnly/e.ts (0 errors) ==== import { ns } from './c'; - ns.A; // Error - ~~ -!!! error TS1362: 'ns' cannot be used as a value because it was exported using 'export type'. -!!! related TS1377 tests/cases/conformance/externalModules/typeOnly/c.ts:1:13: 'ns' was exported here. + ns.A; \ No newline at end of file diff --git a/tests/baselines/reference/exportNamespace4.js b/tests/baselines/reference/exportNamespace4.js index d17adcc51176a..e7da4ca86d055 100644 --- a/tests/baselines/reference/exportNamespace4.js +++ b/tests/baselines/reference/exportNamespace4.js @@ -11,11 +11,11 @@ export type * as ns from './a'; // Grammar error //// [d.ts] import { A } from './b'; -A; // Error +A; //// [e.ts] import { ns } from './c'; -ns.A; // Error +ns.A; //// [a.js] @@ -36,8 +36,10 @@ exports.__esModule = true; //// [d.js] "use strict"; exports.__esModule = true; -A; // Error +var b_1 = require("./b"); +b_1.A; //// [e.js] "use strict"; exports.__esModule = true; -ns.A; // Error +var c_1 = require("./c"); +c_1.ns.A; diff --git a/tests/baselines/reference/exportNamespace4.symbols b/tests/baselines/reference/exportNamespace4.symbols index c93887db8aa5a..860bb80b87795 100644 --- a/tests/baselines/reference/exportNamespace4.symbols +++ b/tests/baselines/reference/exportNamespace4.symbols @@ -13,14 +13,14 @@ export type * as ns from './a'; // Grammar error import { A } from './b'; >A : Symbol(A, Decl(d.ts, 0, 8)) -A; // Error +A; >A : Symbol(A, Decl(d.ts, 0, 8)) === tests/cases/conformance/externalModules/typeOnly/e.ts === import { ns } from './c'; >ns : Symbol(ns, Decl(e.ts, 0, 8)) -ns.A; // Error +ns.A; >ns.A : Symbol(ns.A, Decl(a.ts, 0, 0)) >ns : Symbol(ns, Decl(e.ts, 0, 8)) >A : Symbol(ns.A, Decl(a.ts, 0, 0)) diff --git a/tests/baselines/reference/exportNamespace4.types b/tests/baselines/reference/exportNamespace4.types index 897dd4cc3c796..18155fb4eb6e8 100644 --- a/tests/baselines/reference/exportNamespace4.types +++ b/tests/baselines/reference/exportNamespace4.types @@ -13,14 +13,14 @@ export type * as ns from './a'; // Grammar error import { A } from './b'; >A : typeof A -A; // Error +A; >A : typeof A === tests/cases/conformance/externalModules/typeOnly/e.ts === import { ns } from './c'; >ns : typeof ns -ns.A; // Error +ns.A; >ns.A : typeof ns.A >ns : typeof ns >A : typeof ns.A diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts index 3f708ce0d54e2..889552e6643fe 100644 --- a/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts +++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace4.ts @@ -9,8 +9,8 @@ export type * as ns from './a'; // Grammar error // @Filename: d.ts import { A } from './b'; -A; // Error +A; // @Filename: e.ts import { ns } from './c'; -ns.A; // Error +ns.A; From 0c7831d66098289bcaf320485383475b03c56643 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 27 Feb 2020 11:36:18 -0800 Subject: [PATCH 4/4] Revert more --- src/compiler/checker.ts | 10 ++++------ src/compiler/utilities.ts | 3 +-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 514b5af7d2fea..80ccbf81a78ba 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2295,11 +2295,9 @@ namespace ts { ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here; - // Non-null assertion is safe because `markSymbolOfAliasDeclarationIfTypeOnly` cannot return true - // for an ImportEqualsDeclaration without also being passed a defined symbol. - // `typeOnlyDeclaration.name` will be an Identifier for all valid cases, but may be undefined for - // invalid `export type * ...` syntax. - const name = unescapeLeadingUnderscores(tryCast(typeOnlyDeclaration.name, isIdentifier)?.escapedText ?? resolved!.escapedName); + // Non-null assertion is safe because the optionality comes from ImportClause, + // but if an ImportClause was the typeOnlyDeclaration, it had to have a `name`. + const name = unescapeLeadingUnderscores(typeOnlyDeclaration.name!.escapedText); addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)); } } @@ -2730,7 +2728,7 @@ namespace ts { } /** Indicates that a symbol directly or indirectly resolves to a type-only import or export. */ - function getTypeOnlyAliasDeclaration(symbol: Symbol): TypeOnlyCompatibleAliasDeclaration | NamespaceExport | ExportDeclaration | undefined { + function getTypeOnlyAliasDeclaration(symbol: Symbol): TypeOnlyCompatibleAliasDeclaration | undefined { if (!(symbol.flags & SymbolFlags.Alias)) { return undefined; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index fc72453565194..62801c5bf0022 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6216,8 +6216,7 @@ namespace ts { } export function typeOnlyDeclarationIsExport(typeOnlyDeclaration: Node) { - const kind = typeOnlyDeclaration.kind; - return kind === SyntaxKind.ExportSpecifier || kind === SyntaxKind.NamespaceExport || kind === SyntaxKind.ExportDeclaration; + return typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier; } function isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node: Node) {