diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2217f2f430b82..10cfdb2b26178 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2220,9 +2220,30 @@ namespace ts { function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration, dontResolveAlias: boolean): Symbol | undefined { if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { - return resolveExternalModuleSymbol(resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node))); + const immediate = resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)); + const resolved = resolveExternalModuleSymbol(immediate); + markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); + return resolved; + } + const resolved = getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, dontResolveAlias); + checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node, resolved); + return resolved; + } + + 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 + ? 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 + ? 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); + addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)); } - return getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, dontResolveAlias); } function resolveExportByName(moduleSymbol: Symbol, name: __String, sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, dontResolveAlias: boolean) { @@ -2231,8 +2252,9 @@ namespace ts { return getPropertyOfType(getTypeOfSymbol(exportValue), name); } const exportSymbol = moduleSymbol.exports!.get(name); - markSymbolOfAliasDeclarationIfResolvesToTypeOnly(sourceNode, exportSymbol); - return resolveSymbol(exportSymbol, dontResolveAlias); + const resolved = resolveSymbol(exportSymbol, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly(sourceNode, exportSymbol, resolved, /*overwriteEmpty*/ false); + return resolved; } function isSyntacticDefault(node: Node) { @@ -2272,8 +2294,6 @@ namespace ts { function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol | undefined { const moduleSymbol = resolveExternalModuleName(node, node.parent.moduleSpecifier); - markSymbolOfAliasDeclarationIfTypeOnly(node); - if (moduleSymbol) { let exportDefaultSymbol: Symbol | undefined; if (isShorthandAmbientModuleSymbol(moduleSymbol)) { @@ -2315,16 +2335,21 @@ namespace ts { } else if (hasSyntheticDefault) { // per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present - return resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); + const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly(node, moduleSymbol, resolved, /*overwriteTypeOnly*/ false); + return resolved; } + markSymbolOfAliasDeclarationIfTypeOnly(node, exportDefaultSymbol, /*finalTarget*/ undefined, /*overwriteTypeOnly*/ false); return exportDefaultSymbol; } } function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol | undefined { const moduleSpecifier = node.parent.parent.moduleSpecifier; - markSymbolOfAliasDeclarationIfTypeOnly(node); - return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false); + const immediate = resolveExternalModuleName(node, moduleSpecifier); + const resolved = resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false); + markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); + return resolved; } function getTargetOfNamespaceExport(node: NamespaceExport, dontResolveAlias: boolean): Symbol | undefined { @@ -2370,8 +2395,9 @@ namespace ts { if (symbol.flags & SymbolFlags.Module) { const name = (specifier.propertyName ?? specifier.name).escapedText; const exportSymbol = getExportsOfSymbol(symbol).get(name); - markSymbolOfAliasDeclarationIfResolvesToTypeOnly(specifier, exportSymbol); - return resolveSymbol(exportSymbol, dontResolveAlias); + const resolved = resolveSymbol(exportSymbol, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false); + return resolved; } } @@ -2471,8 +2497,9 @@ namespace ts { } function getTargetOfImportSpecifier(node: ImportSpecifier, dontResolveAlias: boolean): Symbol | undefined { - markSymbolOfAliasDeclarationIfTypeOnly(node); - return getExternalModuleMember(node.parent.parent.parent, node, dontResolveAlias); + const resolved = getExternalModuleMember(node.parent.parent.parent, node, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + return resolved; } function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol { @@ -2480,15 +2507,18 @@ namespace ts { } function getTargetOfExportSpecifier(node: ExportSpecifier, meaning: SymbolFlags, dontResolveAlias?: boolean) { - markSymbolOfAliasDeclarationIfTypeOnly(node); - return node.parent.parent.moduleSpecifier ? + const resolved = node.parent.parent.moduleSpecifier ? getExternalModuleMember(node.parent.parent, node, dontResolveAlias) : resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + return resolved; } function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined { const expression = (isExportAssignment(node) ? node.expression : node.right) as EntityNameExpression | ClassExpression; - return getTargetOfAliasLikeExpression(expression, dontResolveAlias); + const resolved = getTargetOfAliasLikeExpression(expression, dontResolveAlias); + markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + return resolved; } function getTargetOfAliasLikeExpression(expression: Expression, dontResolveAlias: boolean) { @@ -2585,22 +2615,55 @@ namespace ts { return links.target; } - function markSymbolOfAliasDeclarationIfResolvesToTypeOnly(aliasDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, resolvesToSymbol: Symbol | undefined) { - if (!aliasDeclaration || !resolvesToSymbol) return; + /** + * Marks a symbol as type-only if its declaration is syntactically type-only. + * If it is not itself marked type-only, but resolves to a type-only alias + * somewhere in its resolution chain, save a reference to the type-only alias declaration + * so the alias _not_ marked type-only can be identified as _transitively_ type-only. + * + * This function is called on each alias declaration that could be type-only or resolve to + * another type-only alias during `resolveAlias`, so that later, when an alias is used in a + * JS-emitting expression, we can quickly determine if that symbol is effectively type-only + * and issue an error if so. + * + * @param aliasDeclaration The alias declaration not marked as type-only + * has already been marked as not resolving to a type-only alias. Used when recursively resolving qualified + * names of import aliases, e.g. `import C = a.b.C`. If namespace `a` is not found to be type-only, the + * import declaration will initially be marked as not resolving to a type-only symbol. But, namespace `b` + * must still be checked for a type-only marker, overwriting the previous negative result if found. + * @param immediateTarget The symbol to which the alias declaration immediately resolves + * @param finalTarget The symbol to which the alias declaration ultimately resolves + * @param overwriteEmpty Checks `resolvesToSymbol` for type-only declarations even if `aliasDeclaration` + */ + function markSymbolOfAliasDeclarationIfTypeOnly( + aliasDeclaration: Declaration | undefined, + immediateTarget: Symbol | undefined, + finalTarget: Symbol | undefined, + overwriteEmpty: boolean, + ): boolean { + if (!aliasDeclaration) return false; + + // If the declaration itself is type-only, mark it and return. + // No need to check what it resolves to. const sourceSymbol = getSymbolOfNode(aliasDeclaration); - const links = getSymbolLinks(sourceSymbol); - if (links.typeOnlyDeclaration === undefined) { - const typeOnly = find(resolvesToSymbol.declarations, isTypeOnlyImportOrExportDeclaration); - links.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(resolvesToSymbol).typeOnlyDeclaration ?? false; + if (isTypeOnlyImportOrExportDeclaration(aliasDeclaration)) { + const links = getSymbolLinks(sourceSymbol); + links.typeOnlyDeclaration = aliasDeclaration; + return true; } + + const links = getSymbolLinks(sourceSymbol); + return markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, immediateTarget, overwriteEmpty) + || markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, finalTarget, overwriteEmpty); } - function markSymbolOfAliasDeclarationIfTypeOnly(aliasDeclaration: TypeOnlyCompatibleAliasDeclaration) { - if (isTypeOnlyImportOrExportDeclaration(aliasDeclaration)) { - const symbol = getSymbolOfNode(aliasDeclaration); - const links = getSymbolLinks(symbol); - links.typeOnlyDeclaration = aliasDeclaration; + function markSymbolOfAliasDeclarationIfTypeOnlyWorker(aliasDeclarationLinks: SymbolLinks, target: Symbol | undefined, overwriteEmpty: boolean): boolean { + if (target && (aliasDeclarationLinks.typeOnlyDeclaration === undefined || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration === false)) { + const exportSymbol = target.exports?.get(InternalSymbolName.ExportEquals) ?? target; + const typeOnly = exportSymbol.declarations && find(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration); + aliasDeclarationLinks.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(exportSymbol).typeOnlyDeclaration ?? false; } + return !!aliasDeclarationLinks.typeOnlyDeclaration; } /** Indicates that a symbol directly or indirectly resolves to a type-only import or export. */ @@ -2738,8 +2801,8 @@ namespace ts { throw Debug.assertNever(name, "Unknown entity name kind."); } Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); - if (isIdentifier(name) && symbol.flags & SymbolFlags.Alias) { - markSymbolOfAliasDeclarationIfResolvesToTypeOnly(getTypeOnlyCompatibleAliasDeclarationFromName(name), symbol); + if (isEntityName(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) { + markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ true); } return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol); } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 8d31323a5d8c0..779d079d7d387 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2011,4 +2011,4 @@ namespace ts { } } } -} \ No newline at end of file +} diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 43077e61e6864..2dc894e71fb50 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1127,6 +1127,14 @@ "category": "Error", "code": 1378 }, + "An import alias cannot reference a declaration that was exported using 'export type'.": { + "category": "Error", + "code": 1379 + }, + "An import alias cannot reference a declaration that was imported using 'import type'.": { + "category": "Error", + "code": 1380 + }, "The types of '{0}' are incompatible between these types.": { "category": "Error", diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e8883714a53e3..c3cadfa617930 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1778,25 +1778,6 @@ namespace ts { return node.kind === SyntaxKind.TypeQuery; } - export function isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node: Node) { - while (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) { - node = node.parent; - } - if (node.kind !== SyntaxKind.ComputedPropertyName) { - return false; - } - if (hasModifier(node.parent, ModifierFlags.Abstract)) { - return true; - } - const containerKind = node.parent.parent.kind; - return containerKind === SyntaxKind.InterfaceDeclaration || containerKind === SyntaxKind.TypeLiteral; - } - - export function isFirstIdentifierOfImplementsClause(node: Node) { - return node.parent?.parent?.parent?.kind === SyntaxKind.HeritageClause - && (node.parent.parent.parent as HeritageClause).token === SyntaxKind.ImplementsKeyword; - } - export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } { return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference; } @@ -2738,13 +2719,47 @@ namespace ts { return false; } - export function getTypeOnlyCompatibleAliasDeclarationFromName(node: Identifier): TypeOnlyCompatibleAliasDeclaration | undefined { + // An alias symbol is created by one of the following declarations: + // import = ... + // import from ... + // import * as from ... + // import { x as } from ... + // export { x as } from ... + // export * as ns from ... + // export = + // export default + // module.exports = + // {} + // {name: } + export function isAliasSymbolDeclaration(node: Node): boolean { + return node.kind === SyntaxKind.ImportEqualsDeclaration || + node.kind === SyntaxKind.NamespaceExportDeclaration || + node.kind === SyntaxKind.ImportClause && !!(node).name || + node.kind === SyntaxKind.NamespaceImport || + node.kind === SyntaxKind.NamespaceExport || + node.kind === SyntaxKind.ImportSpecifier || + node.kind === SyntaxKind.ExportSpecifier || + node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node) || + isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) || + isPropertyAccessExpression(node) && isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAliasableExpression(node.parent.right) || + node.kind === SyntaxKind.ShorthandPropertyAssignment || + node.kind === SyntaxKind.PropertyAssignment && isAliasableExpression((node as PropertyAssignment).initializer); + } + + export function getAliasDeclarationFromName(node: EntityName): Declaration | undefined { switch (node.parent.kind) { case SyntaxKind.ImportClause: case SyntaxKind.ImportSpecifier: case SyntaxKind.NamespaceImport: case SyntaxKind.ExportSpecifier: - return node.parent as TypeOnlyCompatibleAliasDeclaration; + case SyntaxKind.ExportAssignment: + case SyntaxKind.ImportEqualsDeclaration: + return node.parent as Declaration; + case SyntaxKind.QualifiedName: + do { + node = node.parent as QualifiedName; + } while (node.parent.kind === SyntaxKind.QualifiedName); + return getAliasDeclarationFromName(node); } } @@ -6116,8 +6131,29 @@ namespace ts { export function isValidTypeOnlyAliasUseSite(useSite: Node): boolean { return !!(useSite.flags & NodeFlags.Ambient) || isPartOfTypeQuery(useSite) - || isFirstIdentifierOfImplementsClause(useSite) + || isFirstIdentifierOfNonEmittingHeritageClause(useSite) || isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(useSite) || !isExpressionNode(useSite); } + + function isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node: Node) { + while (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) { + node = node.parent; + } + if (node.kind !== SyntaxKind.ComputedPropertyName) { + return false; + } + if (hasModifier(node.parent, ModifierFlags.Abstract)) { + return true; + } + const containerKind = node.parent.parent.kind; + return containerKind === SyntaxKind.InterfaceDeclaration || containerKind === SyntaxKind.TypeLiteral; + } + + /** Returns true for the first identifier of 1) an `implements` clause, and 2) an `extends` clause of an interface. */ + function isFirstIdentifierOfNonEmittingHeritageClause(node: Node): boolean { + // Number of parents to climb from identifier is 2 for `implements I`, 3 for `implements x.I` + const heritageClause = tryCast(node.parent.parent, isHeritageClause) ?? tryCast(node.parent.parent?.parent, isHeritageClause); + return heritageClause?.token === SyntaxKind.ImplementsKeyword || heritageClause?.parent.kind === SyntaxKind.InterfaceDeclaration; + } } diff --git a/src/testRunner/tsconfig.json b/src/testRunner/tsconfig.json index 3c3bdf0deb6f8..7b05f9cd270f8 100644 --- a/src/testRunner/tsconfig.json +++ b/src/testRunner/tsconfig.json @@ -186,6 +186,7 @@ "unittests/tsserver/textStorage.ts", "unittests/tsserver/telemetry.ts", "unittests/tsserver/typeAquisition.ts", + "unittests/tsserver/typeOnlyImportChains.ts", "unittests/tsserver/typeReferenceDirectives.ts", "unittests/tsserver/typingsInstaller.ts", "unittests/tsserver/untitledFiles.ts", diff --git a/src/testRunner/unittests/tsserver/typeOnlyImportChains.ts b/src/testRunner/unittests/tsserver/typeOnlyImportChains.ts new file mode 100644 index 0000000000000..7c484983f8535 --- /dev/null +++ b/src/testRunner/unittests/tsserver/typeOnlyImportChains.ts @@ -0,0 +1,104 @@ +namespace ts.projectSystem { + describe("unittests:: tsserver:: typeOnlyImportChains", () => { + it("named export -> type-only namespace import -> named export -> named import", () => { + const a = { + path: "/a.ts", + content: "export class A {}" + }; + const b = { + path: "/b.ts", + content: "import type * as a from './a'; export { a };" + }; + const c = { + path: "/c.ts", + content: "import { a } from './b'; new a.A();" + }; + + assertUsageError([a, b, c], c); + }); + + it("named export -> type-only named import -> named export -> named import", () => { + const a = { + path: "/a.ts", + content: "export class A {}" + }; + const b = { + path: "/b.ts", + content: "import type { A } from './a'; export { A };" + }; + const c = { + path: "/c.ts", + content: "import { A } from './b'; new A();" + }; + + assertUsageError([a, b, c], c); + }); + + it("named export -> type-only namespace import -> export equals -> import equals", () => { + const a = { + path: "/a.ts", + content: "export class A {}" + }; + const b = { + path: "/b.ts", + content: "import type * as a from './a'; export = a;" + }; + const c = { + path: "/c.ts", + content: "import a = require('./b'); new a.A();" + }; + + assertUsageError([a, b, c], c); + }); + + it("named export -> type-only namespace import -> export default -> import default", () => { + const a = { + path: "/a.ts", + content: "export class A {}" + }; + const b = { + path: "/b.ts", + content: "import type * as a from './a'; export default a;" + }; + const c = { + path: "/c.ts", + content: "import a from './b'; new a.A();" + }; + + assertUsageError([a, b, c], c); + }); + + it("export default -> type-only import default -> export default -> import default", () => { + const a = { + path: "/a.ts", + content: "export defai;t class A {}" + }; + const b = { + path: "/b.ts", + content: "import type A from './a'; export default A;" + }; + const c = { + path: "/c.ts", + content: "import A from './b'; new A();" + }; + + assertUsageError([a, b, c], c); + }); + }); + + function assertUsageError(files: readonly TestFSWithWatch.File[], openFile: TestFSWithWatch.File) { + const host = createServerHost(files); + const session = createSession(host); + openFilesForSession([openFile], session); + const req = makeSessionRequest( + protocol.CommandTypes.SemanticDiagnosticsSync, + { file: openFile.path } + ); + const diagnostics = session.executeCommand(req).response as protocol.Diagnostic[]; + assert.lengthOf(diagnostics, 1); + assert.oneOf(diagnostics[0].code, [ + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type.code, + Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type.code + ]); + } +} diff --git a/tests/baselines/reference/exportDefault.errors.txt b/tests/baselines/reference/exportDefault.errors.txt new file mode 100644 index 0000000000000..bd39d7a43c938 --- /dev/null +++ b/tests/baselines/reference/exportDefault.errors.txt @@ -0,0 +1,43 @@ +/d.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +/e.ts(2,11): error TS2339: Property 'A' does not exist on type 'typeof import("/b")'. +/f.ts(2,11): error TS2339: Property 'default' does not exist on type 'typeof import("/b")'. +/g.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. + + +==== /a.ts (0 errors) ==== + export class A {} + +==== /b.ts (0 errors) ==== + import type * as types from './a'; + export default types; + +==== /c.ts (0 errors) ==== + import * as types from './a'; + export default types; + +==== /d.ts (1 errors) ==== + import types from './b'; + new types.A(); // Error + ~~~~~ +!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 /b.ts:1:13: 'types' was imported here. + +==== /e.ts (1 errors) ==== + import types = require('./b'); + new types.A(); // Error + ~ +!!! error TS2339: Property 'A' does not exist on type 'typeof import("/b")'. + +==== /f.ts (1 errors) ==== + import * as types from './b'; + new types.default.A(); // Error + ~~~~~~~ +!!! error TS2339: Property 'default' does not exist on type 'typeof import("/b")'. + +==== /g.ts (1 errors) ==== + import type types from './c' + new types.A(); // Error + ~~~~~ +!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 /g.ts:1:8: 'types' was imported here. + \ No newline at end of file diff --git a/tests/baselines/reference/exportDefault.js b/tests/baselines/reference/exportDefault.js new file mode 100644 index 0000000000000..ed91b0f593e81 --- /dev/null +++ b/tests/baselines/reference/exportDefault.js @@ -0,0 +1,80 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportDefault.ts] //// + +//// [a.ts] +export class A {} + +//// [b.ts] +import type * as types from './a'; +export default types; + +//// [c.ts] +import * as types from './a'; +export default types; + +//// [d.ts] +import types from './b'; +new types.A(); // Error + +//// [e.ts] +import types = require('./b'); +new types.A(); // Error + +//// [f.ts] +import * as types from './b'; +new types.default.A(); // Error + +//// [g.ts] +import type types from './c' +new types.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; +exports["default"] = types; +//// [c.js] +"use strict"; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +exports.__esModule = true; +var types = __importStar(require("./a")); +exports["default"] = types; +//// [d.js] +"use strict"; +exports.__esModule = true; +new types.A(); // Error +//// [e.js] +"use strict"; +exports.__esModule = true; +var types = require("./b"); +new types.A(); // Error +//// [f.js] +"use strict"; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +exports.__esModule = true; +var types = __importStar(require("./b")); +new types["default"].A(); // Error +//// [g.js] +"use strict"; +exports.__esModule = true; +new types.A(); // Error diff --git a/tests/baselines/reference/exportDefault.symbols b/tests/baselines/reference/exportDefault.symbols new file mode 100644 index 0000000000000..6d2b5a72bd7ad --- /dev/null +++ b/tests/baselines/reference/exportDefault.symbols @@ -0,0 +1,50 @@ +=== /a.ts === +export class A {} +>A : Symbol(A, Decl(a.ts, 0, 0)) + +=== /b.ts === +import type * as types from './a'; +>types : Symbol(types, Decl(b.ts, 0, 11)) + +export default types; +>types : Symbol(types, Decl(b.ts, 0, 11)) + +=== /c.ts === +import * as types from './a'; +>types : Symbol(types, Decl(c.ts, 0, 6)) + +export default types; +>types : Symbol(types, Decl(c.ts, 0, 6)) + +=== /d.ts === +import types from './b'; +>types : Symbol(types, Decl(d.ts, 0, 6)) + +new types.A(); // Error +>types.A : Symbol(types.A, Decl(a.ts, 0, 0)) +>types : Symbol(types, Decl(d.ts, 0, 6)) +>A : Symbol(types.A, Decl(a.ts, 0, 0)) + +=== /e.ts === +import types = require('./b'); +>types : Symbol(types, Decl(e.ts, 0, 0)) + +new types.A(); // Error +>types : Symbol(types, Decl(e.ts, 0, 0)) + +=== /f.ts === +import * as types from './b'; +>types : Symbol(types, Decl(f.ts, 0, 6)) + +new types.default.A(); // Error +>types : Symbol(types, Decl(f.ts, 0, 6)) + +=== /g.ts === +import type types from './c' +>types : Symbol(types, Decl(g.ts, 0, 6)) + +new types.A(); // Error +>types.A : Symbol(types.A, Decl(a.ts, 0, 0)) +>types : Symbol(types, Decl(g.ts, 0, 6)) +>A : Symbol(types.A, Decl(a.ts, 0, 0)) + diff --git a/tests/baselines/reference/exportDefault.types b/tests/baselines/reference/exportDefault.types new file mode 100644 index 0000000000000..5fcdb6460115c --- /dev/null +++ b/tests/baselines/reference/exportDefault.types @@ -0,0 +1,60 @@ +=== /a.ts === +export class A {} +>A : A + +=== /b.ts === +import type * as types from './a'; +>types : typeof types + +export default types; +>types : typeof types + +=== /c.ts === +import * as types from './a'; +>types : typeof types + +export default types; +>types : typeof types + +=== /d.ts === +import types from './b'; +>types : typeof types + +new types.A(); // Error +>new types.A() : types.A +>types.A : typeof types.A +>types : typeof types +>A : typeof types.A + +=== /e.ts === +import types = require('./b'); +>types : typeof types + +new types.A(); // Error +>new types.A() : any +>types.A : any +>types : typeof types +>A : any + +=== /f.ts === +import * as types from './b'; +>types : typeof types + +new types.default.A(); // Error +>new types.default.A() : any +>types.default.A : any +>types.default : any +>types : typeof types +>default : any +>A : any + +=== /g.ts === +import type types from './c' +>types : any + +new types.A(); // Error +>new types.A() : types.A +>types.A : typeof types.A +>types : typeof types +>A : typeof types.A + diff --git a/tests/baselines/reference/extendsClause.errors.txt b/tests/baselines/reference/extendsClause.errors.txt new file mode 100644 index 0000000000000..7ee2b0600c360 --- /dev/null +++ b/tests/baselines/reference/extendsClause.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/externalModules/typeOnly/index.ts(9,17): error TS1361: 'C' cannot be used as a value because it was imported using 'import type'. +tests/cases/conformance/externalModules/typeOnly/index.ts(10,17): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. + + +==== tests/cases/conformance/externalModules/typeOnly/types.ts (0 errors) ==== + export interface I {} + export class C {} + +==== tests/cases/conformance/externalModules/typeOnly/ns.ts (0 errors) ==== + import type * as types from './types'; + export { types }; + +==== tests/cases/conformance/externalModules/typeOnly/index.ts (2 errors) ==== + import { types } from './ns'; + import type { C, I } from './types'; + + interface Q extends C {} + interface R extends I {} + interface S extends types.C {} + interface T extends types.I {} + + class U extends C {} // Error + ~ +!!! error TS1361: 'C' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/index.ts:2:15: 'C' was imported here. + class V extends types.C {} // Error + ~~~~~ +!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/ns.ts:1:13: 'types' was imported here. + \ No newline at end of file diff --git a/tests/baselines/reference/extendsClause.js b/tests/baselines/reference/extendsClause.js new file mode 100644 index 0000000000000..d4b31c0484074 --- /dev/null +++ b/tests/baselines/reference/extendsClause.js @@ -0,0 +1,65 @@ +//// [tests/cases/conformance/externalModules/typeOnly/extendsClause.ts] //// + +//// [types.ts] +export interface I {} +export class C {} + +//// [ns.ts] +import type * as types from './types'; +export { types }; + +//// [index.ts] +import { types } from './ns'; +import type { C, I } from './types'; + +interface Q extends C {} +interface R extends I {} +interface S extends types.C {} +interface T extends types.I {} + +class U extends C {} // Error +class V extends types.C {} // Error + + +//// [types.js] +"use strict"; +exports.__esModule = true; +var C = /** @class */ (function () { + function C() { + } + return C; +}()); +exports.C = C; +//// [ns.js] +"use strict"; +exports.__esModule = true; +//// [index.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +var U = /** @class */ (function (_super) { + __extends(U, _super); + function U() { + return _super !== null && _super.apply(this, arguments) || this; + } + return U; +}(C)); // Error +var V = /** @class */ (function (_super) { + __extends(V, _super); + function V() { + return _super !== null && _super.apply(this, arguments) || this; + } + return V; +}(types.C)); // Error diff --git a/tests/baselines/reference/extendsClause.symbols b/tests/baselines/reference/extendsClause.symbols new file mode 100644 index 0000000000000..9a9e53d4debba --- /dev/null +++ b/tests/baselines/reference/extendsClause.symbols @@ -0,0 +1,52 @@ +=== tests/cases/conformance/externalModules/typeOnly/types.ts === +export interface I {} +>I : Symbol(I, Decl(types.ts, 0, 0)) + +export class C {} +>C : Symbol(C, Decl(types.ts, 0, 21)) + +=== tests/cases/conformance/externalModules/typeOnly/ns.ts === +import type * as types from './types'; +>types : Symbol(types, Decl(ns.ts, 0, 11)) + +export { types }; +>types : Symbol(types, Decl(ns.ts, 1, 8)) + +=== tests/cases/conformance/externalModules/typeOnly/index.ts === +import { types } from './ns'; +>types : Symbol(types, Decl(index.ts, 0, 8)) + +import type { C, I } from './types'; +>C : Symbol(C, Decl(index.ts, 1, 13)) +>I : Symbol(I, Decl(index.ts, 1, 16)) + +interface Q extends C {} +>Q : Symbol(Q, Decl(index.ts, 1, 36)) +>C : Symbol(C, Decl(index.ts, 1, 13)) + +interface R extends I {} +>R : Symbol(R, Decl(index.ts, 3, 24)) +>I : Symbol(I, Decl(index.ts, 1, 16)) + +interface S extends types.C {} +>S : Symbol(S, Decl(index.ts, 4, 24)) +>types.C : Symbol(types.C, Decl(types.ts, 0, 21)) +>types : Symbol(types, Decl(index.ts, 0, 8)) +>C : Symbol(types.C, Decl(types.ts, 0, 21)) + +interface T extends types.I {} +>T : Symbol(T, Decl(index.ts, 5, 30)) +>types.I : Symbol(types.I, Decl(types.ts, 0, 0)) +>types : Symbol(types, Decl(index.ts, 0, 8)) +>I : Symbol(types.I, Decl(types.ts, 0, 0)) + +class U extends C {} // Error +>U : Symbol(U, Decl(index.ts, 6, 30)) +>C : Symbol(C, Decl(index.ts, 1, 13)) + +class V extends types.C {} // Error +>V : Symbol(V, Decl(index.ts, 8, 20)) +>types.C : Symbol(types.C, Decl(types.ts, 0, 21)) +>types : Symbol(types, Decl(index.ts, 0, 8)) +>C : Symbol(types.C, Decl(types.ts, 0, 21)) + diff --git a/tests/baselines/reference/extendsClause.types b/tests/baselines/reference/extendsClause.types new file mode 100644 index 0000000000000..15140fd0fd6a8 --- /dev/null +++ b/tests/baselines/reference/extendsClause.types @@ -0,0 +1,38 @@ +=== tests/cases/conformance/externalModules/typeOnly/types.ts === +export interface I {} +export class C {} +>C : C + +=== tests/cases/conformance/externalModules/typeOnly/ns.ts === +import type * as types from './types'; +>types : typeof types + +export { types }; +>types : typeof types + +=== tests/cases/conformance/externalModules/typeOnly/index.ts === +import { types } from './ns'; +>types : typeof types + +import type { C, I } from './types'; +>C : types.C +>I : types.I + +interface Q extends C {} +interface R extends I {} +interface S extends types.C {} +>types : typeof types + +interface T extends types.I {} +>types : typeof types + +class U extends C {} // Error +>U : U +>C : types.C + +class V extends types.C {} // Error +>V : V +>types.C : types.C +>types : typeof types +>C : typeof types.C + diff --git a/tests/baselines/reference/importEquals1.errors.txt b/tests/baselines/reference/importEquals1.errors.txt new file mode 100644 index 0000000000000..8585ff46594de --- /dev/null +++ b/tests/baselines/reference/importEquals1.errors.txt @@ -0,0 +1,45 @@ +/d.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +/e.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +/f.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +/g.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. + + +==== /a.ts (0 errors) ==== + export class A {} + +==== /b.ts (0 errors) ==== + import type * as types from './a'; + export = types; // Error + +==== /c.ts (0 errors) ==== + import * as types from './a'; + export = types; + +==== /d.ts (1 errors) ==== + import types from './b'; + new types.A(); // Error + ~~~~~ +!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 /b.ts:1:13: 'types' was imported here. + +==== /e.ts (1 errors) ==== + import types = require('./b'); + new types.A(); // Error + ~~~~~ +!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 /b.ts:1:13: 'types' was imported here. + +==== /f.ts (1 errors) ==== + import * as types from './b'; + new types.A(); // Error + ~~~~~ +!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 /b.ts:1:13: 'types' was imported here. + +==== /g.ts (1 errors) ==== + import type types from './c' + new types.A(); // Error + ~~~~~ +!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'. +!!! related TS1376 /g.ts:1:8: 'types' was imported here. + \ No newline at end of file diff --git a/tests/baselines/reference/importEquals1.js b/tests/baselines/reference/importEquals1.js new file mode 100644 index 0000000000000..1789b73d58f3d --- /dev/null +++ b/tests/baselines/reference/importEquals1.js @@ -0,0 +1,69 @@ +//// [tests/cases/conformance/externalModules/typeOnly/importEquals1.ts] //// + +//// [a.ts] +export class A {} + +//// [b.ts] +import type * as types from './a'; +export = types; // Error + +//// [c.ts] +import * as types from './a'; +export = types; + +//// [d.ts] +import types from './b'; +new types.A(); // Error + +//// [e.ts] +import types = require('./b'); +new types.A(); // Error + +//// [f.ts] +import * as types from './b'; +new types.A(); // Error + +//// [g.ts] +import type types from './c' +new types.A(); // Error + + +//// [a.js] +"use strict"; +exports.__esModule = true; +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +exports.A = A; +//// [b.js] +"use strict"; +module.exports = types; +//// [c.js] +"use strict"; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +var types = __importStar(require("./a")); +module.exports = types; +//// [d.js] +"use strict"; +exports.__esModule = true; +new types.A(); // Error +//// [e.js] +"use strict"; +exports.__esModule = true; +new types.A(); // Error +//// [f.js] +"use strict"; +exports.__esModule = true; +new types.A(); // Error +//// [g.js] +"use strict"; +exports.__esModule = true; +new types.A(); // Error diff --git a/tests/baselines/reference/importEquals1.symbols b/tests/baselines/reference/importEquals1.symbols new file mode 100644 index 0000000000000..195e8b6e371c3 --- /dev/null +++ b/tests/baselines/reference/importEquals1.symbols @@ -0,0 +1,54 @@ +=== /a.ts === +export class A {} +>A : Symbol(A, Decl(a.ts, 0, 0)) + +=== /b.ts === +import type * as types from './a'; +>types : Symbol(types, Decl(b.ts, 0, 11)) + +export = types; // Error +>types : Symbol(types, Decl(b.ts, 0, 11)) + +=== /c.ts === +import * as types from './a'; +>types : Symbol(types, Decl(c.ts, 0, 6)) + +export = types; +>types : Symbol(types, Decl(c.ts, 0, 6)) + +=== /d.ts === +import types from './b'; +>types : Symbol(types, Decl(d.ts, 0, 6)) + +new types.A(); // Error +>types.A : Symbol(types.A, Decl(a.ts, 0, 0)) +>types : Symbol(types, Decl(d.ts, 0, 6)) +>A : Symbol(types.A, Decl(a.ts, 0, 0)) + +=== /e.ts === +import types = require('./b'); +>types : Symbol(types, Decl(e.ts, 0, 0)) + +new types.A(); // Error +>types.A : Symbol(types.A, Decl(a.ts, 0, 0)) +>types : Symbol(types, Decl(e.ts, 0, 0)) +>A : Symbol(types.A, Decl(a.ts, 0, 0)) + +=== /f.ts === +import * as types from './b'; +>types : Symbol(types, Decl(f.ts, 0, 6)) + +new types.A(); // Error +>types.A : Symbol(types.A, Decl(a.ts, 0, 0)) +>types : Symbol(types, Decl(f.ts, 0, 6)) +>A : Symbol(types.A, Decl(a.ts, 0, 0)) + +=== /g.ts === +import type types from './c' +>types : Symbol(types, Decl(g.ts, 0, 6)) + +new types.A(); // Error +>types.A : Symbol(types.A, Decl(a.ts, 0, 0)) +>types : Symbol(types, Decl(g.ts, 0, 6)) +>A : Symbol(types.A, Decl(a.ts, 0, 0)) + diff --git a/tests/baselines/reference/importEquals1.types b/tests/baselines/reference/importEquals1.types new file mode 100644 index 0000000000000..f9bb4f2697ac0 --- /dev/null +++ b/tests/baselines/reference/importEquals1.types @@ -0,0 +1,58 @@ +=== /a.ts === +export class A {} +>A : A + +=== /b.ts === +import type * as types from './a'; +>types : typeof types + +export = types; // Error +>types : typeof types + +=== /c.ts === +import * as types from './a'; +>types : typeof types + +export = types; +>types : typeof types + +=== /d.ts === +import types from './b'; +>types : typeof types + +new types.A(); // Error +>new types.A() : types.A +>types.A : typeof types.A +>types : typeof types +>A : typeof types.A + +=== /e.ts === +import types = require('./b'); +>types : typeof types + +new types.A(); // Error +>new types.A() : types.A +>types.A : typeof types.A +>types : typeof types +>A : typeof types.A + +=== /f.ts === +import * as types from './b'; +>types : typeof types + +new types.A(); // Error +>new types.A() : types.A +>types.A : typeof types.A +>types : typeof types +>A : typeof types.A + +=== /g.ts === +import type types from './c' +>types : any + +new types.A(); // Error +>new types.A() : types.A +>types.A : typeof types.A +>types : typeof types +>A : typeof types.A + diff --git a/tests/baselines/reference/importEquals2.errors.txt b/tests/baselines/reference/importEquals2.errors.txt new file mode 100644 index 0000000000000..a347e9c04bbe0 --- /dev/null +++ b/tests/baselines/reference/importEquals2.errors.txt @@ -0,0 +1,17 @@ +/c.ts(2,7): error TS2339: Property 'A' does not exist on type 'typeof import("/a")'. + + +==== /c.ts (1 errors) ==== + import a = require('./b'); + new a.A(); // Error + ~ +!!! error TS2339: Property 'A' does not exist on type 'typeof import("/a")'. + +==== /a.ts (0 errors) ==== + class A {} + export type { A } + +==== /b.ts (0 errors) ==== + import * as a from './a'; + export = a; + \ No newline at end of file diff --git a/tests/baselines/reference/importEquals2.js b/tests/baselines/reference/importEquals2.js new file mode 100644 index 0000000000000..05401a6cb539e --- /dev/null +++ b/tests/baselines/reference/importEquals2.js @@ -0,0 +1,39 @@ +//// [tests/cases/conformance/externalModules/typeOnly/importEquals2.ts] //// + +//// [a.ts] +class A {} +export type { A } + +//// [b.ts] +import * as a from './a'; +export = a; + +//// [c.ts] +import a = require('./b'); +new a.A(); // Error + + +//// [a.js] +"use strict"; +exports.__esModule = true; +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +//// [b.js] +"use strict"; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +var a = __importStar(require("./a")); +module.exports = a; +//// [c.js] +"use strict"; +exports.__esModule = true; +var a = require("./b"); +new a.A(); // Error diff --git a/tests/baselines/reference/importEquals2.symbols b/tests/baselines/reference/importEquals2.symbols new file mode 100644 index 0000000000000..84b5dbba668ac --- /dev/null +++ b/tests/baselines/reference/importEquals2.symbols @@ -0,0 +1,21 @@ +=== /c.ts === +import a = require('./b'); +>a : Symbol(a, Decl(c.ts, 0, 0)) + +new a.A(); // Error +>a : Symbol(a, Decl(c.ts, 0, 0)) + +=== /a.ts === +class A {} +>A : Symbol(A, Decl(a.ts, 0, 0)) + +export type { A } +>A : Symbol(A, Decl(a.ts, 1, 13)) + +=== /b.ts === +import * as a from './a'; +>a : Symbol(a, Decl(b.ts, 0, 6)) + +export = a; +>a : Symbol(a, Decl(b.ts, 0, 6)) + diff --git a/tests/baselines/reference/importEquals2.types b/tests/baselines/reference/importEquals2.types new file mode 100644 index 0000000000000..e02fd8846a369 --- /dev/null +++ b/tests/baselines/reference/importEquals2.types @@ -0,0 +1,24 @@ +=== /c.ts === +import a = require('./b'); +>a : typeof a + +new a.A(); // Error +>new a.A() : any +>a.A : any +>a : typeof a +>A : any + +=== /a.ts === +class A {} +>A : A + +export type { A } +>A : A + +=== /b.ts === +import * as a from './a'; +>a : typeof a + +export = a; +>a : typeof a + diff --git a/tests/baselines/reference/importEquals3.errors.txt b/tests/baselines/reference/importEquals3.errors.txt new file mode 100644 index 0000000000000..75ebc4cb19689 --- /dev/null +++ b/tests/baselines/reference/importEquals3.errors.txt @@ -0,0 +1,37 @@ +tests/cases/conformance/externalModules/typeOnly/b.ts(2,12): error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. +tests/cases/conformance/externalModules/typeOnly/b.ts(3,13): error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. +tests/cases/conformance/externalModules/typeOnly/c.ts(2,12): error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. +tests/cases/conformance/externalModules/typeOnly/c.ts(3,13): error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. + + +==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ==== + export class A {} + +==== tests/cases/conformance/externalModules/typeOnly/b.ts (2 errors) ==== + import type * as a from './a'; + import A = a.A; // Error + ~~~ +!!! error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. +!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/b.ts:1:13: 'a' was imported here. + import aa = a; // Error + ~ +!!! error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. +!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/b.ts:1:13: 'a' was imported here. + + const x = 0; + export { a, A, x }; + +==== tests/cases/conformance/externalModules/typeOnly/c.ts (2 errors) ==== + import * as b from './b'; + import A = b.a.A; // Error + ~~~~~ +!!! error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. +!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/b.ts:1:13: 'a' was imported here. + import AA = b.A; // Error + ~~~ +!!! error TS1380: An import alias cannot reference a declaration that was imported using 'import type'. +!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/b.ts:1:13: 'a' was imported here. + + import x = b.x; + console.log(x); + \ No newline at end of file diff --git a/tests/baselines/reference/importEquals3.js b/tests/baselines/reference/importEquals3.js new file mode 100644 index 0000000000000..1e76d2dded1e9 --- /dev/null +++ b/tests/baselines/reference/importEquals3.js @@ -0,0 +1,42 @@ +//// [tests/cases/conformance/externalModules/typeOnly/importEquals3.ts] //// + +//// [a.ts] +export class A {} + +//// [b.ts] +import type * as a from './a'; +import A = a.A; // Error +import aa = a; // Error + +const x = 0; +export { a, A, x }; + +//// [c.ts] +import * as b from './b'; +import A = b.a.A; // Error +import AA = b.A; // Error + +import x = b.x; +console.log(x); + + +//// [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; +var x = 0; +exports.x = x; +//// [c.js] +"use strict"; +exports.__esModule = true; +var b = require("./b"); +var x = b.x; +console.log(x); diff --git a/tests/baselines/reference/importEquals3.symbols b/tests/baselines/reference/importEquals3.symbols new file mode 100644 index 0000000000000..28f402d77d7b9 --- /dev/null +++ b/tests/baselines/reference/importEquals3.symbols @@ -0,0 +1,51 @@ +=== 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 === +import type * as a from './a'; +>a : Symbol(a, Decl(b.ts, 0, 11)) + +import A = a.A; // Error +>A : Symbol(A, Decl(b.ts, 0, 30)) +>a : Symbol(a, Decl(b.ts, 0, 11)) +>A : Symbol(a.A, Decl(a.ts, 0, 0)) + +import aa = a; // Error +>aa : Symbol(aa, Decl(b.ts, 1, 15)) +>a : Symbol(a, Decl(b.ts, 0, 11)) + +const x = 0; +>x : Symbol(x, Decl(b.ts, 4, 5)) + +export { a, A, x }; +>a : Symbol(a, Decl(b.ts, 5, 8)) +>A : Symbol(A, Decl(b.ts, 5, 11)) +>x : Symbol(x, Decl(b.ts, 5, 14)) + +=== tests/cases/conformance/externalModules/typeOnly/c.ts === +import * as b from './b'; +>b : Symbol(b, Decl(c.ts, 0, 6)) + +import A = b.a.A; // Error +>A : Symbol(A, Decl(c.ts, 0, 25)) +>b : Symbol(b, Decl(c.ts, 0, 6)) +>a : Symbol(b.a, Decl(b.ts, 5, 8)) +>A : Symbol(b.a.A, Decl(a.ts, 0, 0)) + +import AA = b.A; // Error +>AA : Symbol(AA, Decl(c.ts, 1, 17)) +>b : Symbol(b, Decl(c.ts, 0, 6)) +>A : Symbol(b.A, Decl(b.ts, 5, 11)) + +import x = b.x; +>x : Symbol(x, Decl(c.ts, 2, 16)) +>b : Symbol(b, Decl(c.ts, 0, 6)) +>x : Symbol(b.x, Decl(b.ts, 5, 14)) + +console.log(x); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>x : Symbol(x, Decl(c.ts, 2, 16)) + diff --git a/tests/baselines/reference/importEquals3.types b/tests/baselines/reference/importEquals3.types new file mode 100644 index 0000000000000..ba1eaeefe9514 --- /dev/null +++ b/tests/baselines/reference/importEquals3.types @@ -0,0 +1,53 @@ +=== tests/cases/conformance/externalModules/typeOnly/a.ts === +export class A {} +>A : A + +=== tests/cases/conformance/externalModules/typeOnly/b.ts === +import type * as a from './a'; +>a : typeof a + +import A = a.A; // Error +>A : typeof a.A +>a : typeof a +>A : a.A + +import aa = a; // Error +>aa : typeof a +>a : typeof a + +const x = 0; +>x : 0 +>0 : 0 + +export { a, A, x }; +>a : typeof a +>A : typeof a.A +>x : 0 + +=== tests/cases/conformance/externalModules/typeOnly/c.ts === +import * as b from './b'; +>b : typeof b + +import A = b.a.A; // Error +>A : typeof b.a.A +>b : typeof b +>a : typeof b.a +>A : b.a.A + +import AA = b.A; // Error +>AA : typeof b.a.A +>b : typeof b +>A : b.a.A + +import x = b.x; +>x : 0 +>b : typeof b +>x : 0 + +console.log(x); +>console.log(x) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>x : 0 + diff --git a/tests/cases/conformance/externalModules/typeOnly/exportDefault.ts b/tests/cases/conformance/externalModules/typeOnly/exportDefault.ts new file mode 100644 index 0000000000000..9cbe305676383 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/exportDefault.ts @@ -0,0 +1,28 @@ +// @esModuleInterop: true + +// @Filename: /a.ts +export class A {} + +// @Filename: /b.ts +import type * as types from './a'; +export default types; + +// @Filename: /c.ts +import * as types from './a'; +export default types; + +// @Filename: /d.ts +import types from './b'; +new types.A(); // Error + +// @Filename: /e.ts +import types = require('./b'); +new types.A(); // Error + +// @Filename: /f.ts +import * as types from './b'; +new types.default.A(); // Error + +// @Filename: /g.ts +import type types from './c' +new types.A(); // Error diff --git a/tests/cases/conformance/externalModules/typeOnly/extendsClause.ts b/tests/cases/conformance/externalModules/typeOnly/extendsClause.ts new file mode 100644 index 0000000000000..0288d07a8f8e9 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/extendsClause.ts @@ -0,0 +1,19 @@ +// @Filename: types.ts +export interface I {} +export class C {} + +// @Filename: ns.ts +import type * as types from './types'; +export { types }; + +// @Filename: index.ts +import { types } from './ns'; +import type { C, I } from './types'; + +interface Q extends C {} +interface R extends I {} +interface S extends types.C {} +interface T extends types.I {} + +class U extends C {} // Error +class V extends types.C {} // Error diff --git a/tests/cases/conformance/externalModules/typeOnly/importEquals1.ts b/tests/cases/conformance/externalModules/typeOnly/importEquals1.ts new file mode 100644 index 0000000000000..e4ea63dcb6f17 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/importEquals1.ts @@ -0,0 +1,28 @@ +// @esModuleInterop: true + +// @Filename: /a.ts +export class A {} + +// @Filename: /b.ts +import type * as types from './a'; +export = types; // Error + +// @Filename: /c.ts +import * as types from './a'; +export = types; + +// @Filename: /d.ts +import types from './b'; +new types.A(); // Error + +// @Filename: /e.ts +import types = require('./b'); +new types.A(); // Error + +// @Filename: /f.ts +import * as types from './b'; +new types.A(); // Error + +// @Filename: /g.ts +import type types from './c' +new types.A(); // Error diff --git a/tests/cases/conformance/externalModules/typeOnly/importEquals2.ts b/tests/cases/conformance/externalModules/typeOnly/importEquals2.ts new file mode 100644 index 0000000000000..42f8318c706a8 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/importEquals2.ts @@ -0,0 +1,13 @@ +// @esModuleInterop: true + +// @Filename: /a.ts +class A {} +export type { A } + +// @Filename: /b.ts +import * as a from './a'; +export = a; + +// @Filename: /c.ts +import a = require('./b'); +new a.A(); // Error diff --git a/tests/cases/conformance/externalModules/typeOnly/importEquals3.ts b/tests/cases/conformance/externalModules/typeOnly/importEquals3.ts new file mode 100644 index 0000000000000..2a4613d699e19 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/importEquals3.ts @@ -0,0 +1,18 @@ +// @Filename: a.ts +export class A {} + +// @Filename: b.ts +import type * as a from './a'; +import A = a.A; // Error +import aa = a; // Error + +const x = 0; +export { a, A, x }; + +// @Filename: c.ts +import * as b from './b'; +import A = b.a.A; // Error +import AA = b.A; // Error + +import x = b.x; +console.log(x);