diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dfd117be086..f15fd70378e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14914,6 +14914,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); const symbol = resolved.members.get(name); + if (symbol && !includeTypeOnlyMembers && type.symbol?.flags & SymbolFlags.ValueModule && getSymbolLinks(type.symbol).typeOnlyExportStarMap?.has(name)) { + // If this is the type of a module, `resolved.members.get(name)` might have effectively skipped over + // an `export type * from './foo'`, leaving `symbolIsValue` unable to see that the symbol is being + // viewed through a type-only export. + return undefined; + } if (symbol && symbolIsValue(symbol, includeTypeOnlyMembers)) { return symbol; } diff --git a/tests/baselines/reference/exportNamespace11.errors.txt b/tests/baselines/reference/exportNamespace11.errors.txt new file mode 100644 index 00000000000..28338d4764b --- /dev/null +++ b/tests/baselines/reference/exportNamespace11.errors.txt @@ -0,0 +1,14 @@ +main.ts(2,52): error TS2339: Property 'Ghost' does not exist on type 'typeof import("intermediate")'. + + +==== main.ts (1 errors) ==== + import * as intermediate from './intermediate' + const ghost: intermediate.Ghost = new intermediate.Ghost() + ~~~~~ +!!! error TS2339: Property 'Ghost' does not exist on type 'typeof import("intermediate")'. + +==== intermediate.ts (0 errors) ==== + export type * from './ghost' + +==== ghost.ts (0 errors) ==== + export class Ghost {} \ No newline at end of file diff --git a/tests/baselines/reference/exportNamespace11.js b/tests/baselines/reference/exportNamespace11.js new file mode 100644 index 00000000000..b2b30c103d2 --- /dev/null +++ b/tests/baselines/reference/exportNamespace11.js @@ -0,0 +1,30 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts] //// + +//// [main.ts] +import * as intermediate from './intermediate' +const ghost: intermediate.Ghost = new intermediate.Ghost() + +//// [intermediate.ts] +export type * from './ghost' + +//// [ghost.ts] +export class Ghost {} + +//// [ghost.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Ghost = void 0; +var Ghost = /** @class */ (function () { + function Ghost() { + } + return Ghost; +}()); +exports.Ghost = Ghost; +//// [intermediate.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var intermediate = require("./intermediate"); +var ghost = new intermediate.Ghost(); diff --git a/tests/baselines/reference/exportNamespace11.symbols b/tests/baselines/reference/exportNamespace11.symbols new file mode 100644 index 00000000000..570eebe511c --- /dev/null +++ b/tests/baselines/reference/exportNamespace11.symbols @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts] //// + +=== main.ts === +import * as intermediate from './intermediate' +>intermediate : Symbol(intermediate, Decl(main.ts, 0, 6)) + +const ghost: intermediate.Ghost = new intermediate.Ghost() +>ghost : Symbol(ghost, Decl(main.ts, 1, 5)) +>intermediate : Symbol(intermediate, Decl(main.ts, 0, 6)) +>Ghost : Symbol(intermediate.Ghost, Decl(ghost.ts, 0, 0)) +>intermediate : Symbol(intermediate, Decl(main.ts, 0, 6)) + +=== intermediate.ts === + +export type * from './ghost' + +=== ghost.ts === +export class Ghost {} +>Ghost : Symbol(Ghost, Decl(ghost.ts, 0, 0)) + diff --git a/tests/baselines/reference/exportNamespace11.types b/tests/baselines/reference/exportNamespace11.types new file mode 100644 index 00000000000..3360402e7dc --- /dev/null +++ b/tests/baselines/reference/exportNamespace11.types @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts] //// + +=== main.ts === +import * as intermediate from './intermediate' +>intermediate : typeof intermediate + +const ghost: intermediate.Ghost = new intermediate.Ghost() +>ghost : intermediate.Ghost +>intermediate : any +>new intermediate.Ghost() : any +>intermediate.Ghost : any +>intermediate : typeof intermediate +>Ghost : any + +=== intermediate.ts === + +export type * from './ghost' + +=== ghost.ts === +export class Ghost {} +>Ghost : Ghost + diff --git a/tests/baselines/reference/exportNamespace12.errors.txt b/tests/baselines/reference/exportNamespace12.errors.txt new file mode 100644 index 00000000000..885f1e3acb1 --- /dev/null +++ b/tests/baselines/reference/exportNamespace12.errors.txt @@ -0,0 +1,20 @@ +main.ts(3,13): error TS1362: 'c' cannot be used as a value because it was exported using 'export type'. +main.ts(4,19): error TS2339: Property 'c' does not exist on type 'typeof import("types")'. + + +==== main.ts (2 errors) ==== + import { c } from './types' + import * as types from './types' + console.log(c) // Fails as expected, import is still allowed though. + ~ +!!! error TS1362: 'c' cannot be used as a value because it was exported using 'export type'. +!!! related TS1377 types.ts:1:1: 'c' was exported here. + console.log(types.c) // Expected an error here. + ~ +!!! error TS2339: Property 'c' does not exist on type 'typeof import("types")'. + +==== types.ts (0 errors) ==== + export type * from './values' + +==== values.ts (0 errors) ==== + export const c = 10 \ No newline at end of file diff --git a/tests/baselines/reference/exportNamespace12.js b/tests/baselines/reference/exportNamespace12.js new file mode 100644 index 00000000000..a78bb446062 --- /dev/null +++ b/tests/baselines/reference/exportNamespace12.js @@ -0,0 +1,28 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts] //// + +//// [main.ts] +import { c } from './types' +import * as types from './types' +console.log(c) // Fails as expected, import is still allowed though. +console.log(types.c) // Expected an error here. + +//// [types.ts] +export type * from './values' + +//// [values.ts] +export const c = 10 + +//// [values.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.c = void 0; +exports.c = 10; +//// [types.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var types = require("./types"); +console.log(c); // Fails as expected, import is still allowed though. +console.log(types.c); // Expected an error here. diff --git a/tests/baselines/reference/exportNamespace12.symbols b/tests/baselines/reference/exportNamespace12.symbols new file mode 100644 index 00000000000..a2deb494b17 --- /dev/null +++ b/tests/baselines/reference/exportNamespace12.symbols @@ -0,0 +1,29 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts] //// + +=== main.ts === +import { c } from './types' +>c : Symbol(c, Decl(main.ts, 0, 8)) + +import * as types from './types' +>types : Symbol(types, Decl(main.ts, 1, 6)) + +console.log(c) // Fails as expected, import is still allowed though. +>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, --, --)) +>c : Symbol(c, Decl(main.ts, 0, 8)) + +console.log(types.c) // Expected an error here. +>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, --, --)) +>types : Symbol(types, Decl(main.ts, 1, 6)) + +=== types.ts === + +export type * from './values' + +=== values.ts === +export const c = 10 +>c : Symbol(c, Decl(values.ts, 0, 12)) + diff --git a/tests/baselines/reference/exportNamespace12.types b/tests/baselines/reference/exportNamespace12.types new file mode 100644 index 00000000000..1407a5ae15b --- /dev/null +++ b/tests/baselines/reference/exportNamespace12.types @@ -0,0 +1,34 @@ +//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts] //// + +=== main.ts === +import { c } from './types' +>c : 10 + +import * as types from './types' +>types : typeof types + +console.log(c) // Fails as expected, import is still allowed though. +>console.log(c) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>c : 10 + +console.log(types.c) // Expected an error here. +>console.log(types.c) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>types.c : any +>types : typeof types +>c : any + +=== types.ts === + +export type * from './values' + +=== values.ts === +export const c = 10 +>c : 10 +>10 : 10 + diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts new file mode 100644 index 00000000000..745d91c4a24 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts @@ -0,0 +1,9 @@ +// @filename: main.ts +import * as intermediate from './intermediate' +const ghost: intermediate.Ghost = new intermediate.Ghost() + +// @filename: intermediate.ts +export type * from './ghost' + +// @filename: ghost.ts +export class Ghost {} \ No newline at end of file diff --git a/tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts b/tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts new file mode 100644 index 00000000000..6bc7ba5bbaa --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts @@ -0,0 +1,11 @@ +// @filename: main.ts +import { c } from './types' +import * as types from './types' +console.log(c) // Fails as expected, import is still allowed though. +console.log(types.c) // Expected an error here. + +// @filename: types.ts +export type * from './values' + +// @filename: values.ts +export const c = 10 \ No newline at end of file