Skip to content

Commit d2d3b24

Browse files
authored
Fix missing error for accessing type-only export * member through namespace (#57176)
1 parent d21b1d2 commit d2d3b24

File tree

11 files changed

+223
-0
lines changed

11 files changed

+223
-0
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14914,6 +14914,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1491414914
if (type.flags & TypeFlags.Object) {
1491514915
const resolved = resolveStructuredTypeMembers(type as ObjectType);
1491614916
const symbol = resolved.members.get(name);
14917+
if (symbol && !includeTypeOnlyMembers && type.symbol?.flags & SymbolFlags.ValueModule && getSymbolLinks(type.symbol).typeOnlyExportStarMap?.has(name)) {
14918+
// If this is the type of a module, `resolved.members.get(name)` might have effectively skipped over
14919+
// an `export type * from './foo'`, leaving `symbolIsValue` unable to see that the symbol is being
14920+
// viewed through a type-only export.
14921+
return undefined;
14922+
}
1491714923
if (symbol && symbolIsValue(symbol, includeTypeOnlyMembers)) {
1491814924
return symbol;
1491914925
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
main.ts(2,52): error TS2339: Property 'Ghost' does not exist on type 'typeof import("intermediate")'.
2+
3+
4+
==== main.ts (1 errors) ====
5+
import * as intermediate from './intermediate'
6+
const ghost: intermediate.Ghost = new intermediate.Ghost()
7+
~~~~~
8+
!!! error TS2339: Property 'Ghost' does not exist on type 'typeof import("intermediate")'.
9+
10+
==== intermediate.ts (0 errors) ====
11+
export type * from './ghost'
12+
13+
==== ghost.ts (0 errors) ====
14+
export class Ghost {}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts] ////
2+
3+
//// [main.ts]
4+
import * as intermediate from './intermediate'
5+
const ghost: intermediate.Ghost = new intermediate.Ghost()
6+
7+
//// [intermediate.ts]
8+
export type * from './ghost'
9+
10+
//// [ghost.ts]
11+
export class Ghost {}
12+
13+
//// [ghost.js]
14+
"use strict";
15+
Object.defineProperty(exports, "__esModule", { value: true });
16+
exports.Ghost = void 0;
17+
var Ghost = /** @class */ (function () {
18+
function Ghost() {
19+
}
20+
return Ghost;
21+
}());
22+
exports.Ghost = Ghost;
23+
//// [intermediate.js]
24+
"use strict";
25+
Object.defineProperty(exports, "__esModule", { value: true });
26+
//// [main.js]
27+
"use strict";
28+
Object.defineProperty(exports, "__esModule", { value: true });
29+
var intermediate = require("./intermediate");
30+
var ghost = new intermediate.Ghost();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts] ////
2+
3+
=== main.ts ===
4+
import * as intermediate from './intermediate'
5+
>intermediate : Symbol(intermediate, Decl(main.ts, 0, 6))
6+
7+
const ghost: intermediate.Ghost = new intermediate.Ghost()
8+
>ghost : Symbol(ghost, Decl(main.ts, 1, 5))
9+
>intermediate : Symbol(intermediate, Decl(main.ts, 0, 6))
10+
>Ghost : Symbol(intermediate.Ghost, Decl(ghost.ts, 0, 0))
11+
>intermediate : Symbol(intermediate, Decl(main.ts, 0, 6))
12+
13+
=== intermediate.ts ===
14+
15+
export type * from './ghost'
16+
17+
=== ghost.ts ===
18+
export class Ghost {}
19+
>Ghost : Symbol(Ghost, Decl(ghost.ts, 0, 0))
20+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace11.ts] ////
2+
3+
=== main.ts ===
4+
import * as intermediate from './intermediate'
5+
>intermediate : typeof intermediate
6+
7+
const ghost: intermediate.Ghost = new intermediate.Ghost()
8+
>ghost : intermediate.Ghost
9+
>intermediate : any
10+
>new intermediate.Ghost() : any
11+
>intermediate.Ghost : any
12+
>intermediate : typeof intermediate
13+
>Ghost : any
14+
15+
=== intermediate.ts ===
16+
17+
export type * from './ghost'
18+
19+
=== ghost.ts ===
20+
export class Ghost {}
21+
>Ghost : Ghost
22+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
main.ts(3,13): error TS1362: 'c' cannot be used as a value because it was exported using 'export type'.
2+
main.ts(4,19): error TS2339: Property 'c' does not exist on type 'typeof import("types")'.
3+
4+
5+
==== main.ts (2 errors) ====
6+
import { c } from './types'
7+
import * as types from './types'
8+
console.log(c) // Fails as expected, import is still allowed though.
9+
~
10+
!!! error TS1362: 'c' cannot be used as a value because it was exported using 'export type'.
11+
!!! related TS1377 types.ts:1:1: 'c' was exported here.
12+
console.log(types.c) // Expected an error here.
13+
~
14+
!!! error TS2339: Property 'c' does not exist on type 'typeof import("types")'.
15+
16+
==== types.ts (0 errors) ====
17+
export type * from './values'
18+
19+
==== values.ts (0 errors) ====
20+
export const c = 10
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts] ////
2+
3+
//// [main.ts]
4+
import { c } from './types'
5+
import * as types from './types'
6+
console.log(c) // Fails as expected, import is still allowed though.
7+
console.log(types.c) // Expected an error here.
8+
9+
//// [types.ts]
10+
export type * from './values'
11+
12+
//// [values.ts]
13+
export const c = 10
14+
15+
//// [values.js]
16+
"use strict";
17+
Object.defineProperty(exports, "__esModule", { value: true });
18+
exports.c = void 0;
19+
exports.c = 10;
20+
//// [types.js]
21+
"use strict";
22+
Object.defineProperty(exports, "__esModule", { value: true });
23+
//// [main.js]
24+
"use strict";
25+
Object.defineProperty(exports, "__esModule", { value: true });
26+
var types = require("./types");
27+
console.log(c); // Fails as expected, import is still allowed though.
28+
console.log(types.c); // Expected an error here.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts] ////
2+
3+
=== main.ts ===
4+
import { c } from './types'
5+
>c : Symbol(c, Decl(main.ts, 0, 8))
6+
7+
import * as types from './types'
8+
>types : Symbol(types, Decl(main.ts, 1, 6))
9+
10+
console.log(c) // Fails as expected, import is still allowed though.
11+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
12+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
13+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
14+
>c : Symbol(c, Decl(main.ts, 0, 8))
15+
16+
console.log(types.c) // Expected an error here.
17+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
18+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
19+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
20+
>types : Symbol(types, Decl(main.ts, 1, 6))
21+
22+
=== types.ts ===
23+
24+
export type * from './values'
25+
26+
=== values.ts ===
27+
export const c = 10
28+
>c : Symbol(c, Decl(values.ts, 0, 12))
29+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportNamespace12.ts] ////
2+
3+
=== main.ts ===
4+
import { c } from './types'
5+
>c : 10
6+
7+
import * as types from './types'
8+
>types : typeof types
9+
10+
console.log(c) // Fails as expected, import is still allowed though.
11+
>console.log(c) : void
12+
>console.log : (...data: any[]) => void
13+
>console : Console
14+
>log : (...data: any[]) => void
15+
>c : 10
16+
17+
console.log(types.c) // Expected an error here.
18+
>console.log(types.c) : void
19+
>console.log : (...data: any[]) => void
20+
>console : Console
21+
>log : (...data: any[]) => void
22+
>types.c : any
23+
>types : typeof types
24+
>c : any
25+
26+
=== types.ts ===
27+
28+
export type * from './values'
29+
30+
=== values.ts ===
31+
export const c = 10
32+
>c : 10
33+
>10 : 10
34+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @filename: main.ts
2+
import * as intermediate from './intermediate'
3+
const ghost: intermediate.Ghost = new intermediate.Ghost()
4+
5+
// @filename: intermediate.ts
6+
export type * from './ghost'
7+
8+
// @filename: ghost.ts
9+
export class Ghost {}

0 commit comments

Comments
 (0)