Fix export * that resolves to something type-only (#36558)

* Fix `export *` that resolves to something type-only

* Add same tests but non-tsserver
This commit is contained in:
Andrew Branch
2020-01-31 15:09:27 -08:00
committed by GitHub
parent 8db1d7bc6d
commit 86556d6c03
17 changed files with 412 additions and 13 deletions

View File

@@ -2372,7 +2372,10 @@ namespace ts {
function getTargetOfNamespaceExport(node: NamespaceExport, dontResolveAlias: boolean): Symbol | undefined {
const moduleSpecifier = node.parent.moduleSpecifier;
return moduleSpecifier && resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false);
const immediate = moduleSpecifier && resolveExternalModuleName(node, moduleSpecifier);
const resolved = moduleSpecifier && resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false);
markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false);
return resolved;
}
// This function creates a synthetic symbol that combines the value side of one symbol with the
@@ -2521,7 +2524,9 @@ namespace ts {
}
function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol {
return resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias);
const resolved = resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias);
markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false);
return resolved;
}
function getTargetOfExportSpecifier(node: ExportSpecifier, meaning: SymbolFlags, dontResolveAlias?: boolean) {

View File

@@ -14,7 +14,7 @@ namespace ts.projectSystem {
content: "import { a } from './b'; new a.A();"
};
assertUsageError([a, b, c], c);
assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type);
});
it("named export -> type-only named import -> named export -> named import", () => {
@@ -31,7 +31,7 @@ namespace ts.projectSystem {
content: "import { A } from './b'; new A();"
};
assertUsageError([a, b, c], c);
assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type);
});
it("named export -> type-only namespace import -> export equals -> import equals", () => {
@@ -48,7 +48,7 @@ namespace ts.projectSystem {
content: "import a = require('./b'); new a.A();"
};
assertUsageError([a, b, c], c);
assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type);
});
it("named export -> type-only namespace import -> export default -> import default", () => {
@@ -65,13 +65,13 @@ namespace ts.projectSystem {
content: "import a from './b'; new a.A();"
};
assertUsageError([a, b, c], c);
assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type);
});
it("export default -> type-only import default -> export default -> import default", () => {
const a = {
path: "/a.ts",
content: "export defai;t class A {}"
content: "export default class A {}"
};
const b = {
path: "/b.ts",
@@ -82,11 +82,74 @@ namespace ts.projectSystem {
content: "import A from './b'; new A();"
};
assertUsageError([a, b, c], c);
assertUsageError([a, b, c], c, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type);
});
it("named export -> type-only export from -> export star from -> named import", () => {
const a = {
path: "/a.ts",
content: "export class A {}"
};
const b = {
path: "/b.ts",
content: "export type { A } from './a';"
};
const c = {
path: "/c.ts",
content: "export * from './b';"
};
const d = {
path: "/d.ts",
content: "import { A } from './c'; new A();"
};
assertUsageError([a, b, c, d], d, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type);
});
it("named export -> export namespace from -> type-only named import -> named export -> named import", () => {
const a = {
path: "/a.ts",
content: "export class A {}"
};
const b = {
path: "/b.ts",
content: "export * as a from './a';"
};
const c = {
path: "/c.ts",
content: "import type { a } from './b'; export { a };"
};
const d = {
path: "/d.ts",
content: "import { a } from './c'; new a.A();"
};
assertUsageError([a, b, c, d], d, Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type);
});
it("named export -> type-only export from -> export namespace from -> named import", () => {
const a = {
path: "/a.ts",
content: "export class A {}"
};
const b = {
path: "/b.ts",
content: "export type { A } from './a';"
};
const c = {
path: "/c.ts",
content: "export * as a from './b';"
};
const d = {
path: "/d.ts",
content: "import { a } from './c'; new a.A();"
};
assertUsageError([a, b, c, d], d, Diagnostics.Property_0_does_not_exist_on_type_1);
});
});
function assertUsageError(files: readonly TestFSWithWatch.File[], openFile: TestFSWithWatch.File) {
function assertUsageError(files: readonly TestFSWithWatch.File[], openFile: TestFSWithWatch.File, diagnostic: DiagnosticMessage) {
const host = createServerHost(files);
const session = createSession(host);
openFilesForSession([openFile], session);
@@ -96,9 +159,6 @@ namespace ts.projectSystem {
);
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
]);
assert.equal(diagnostics[0].code, diagnostic.code);
}
}