Skip to content

Commit 419dba1

Browse files
committed
Fix import= something type only from a module
1 parent 7e1382a commit 419dba1

12 files changed

+397
-12
lines changed

src/compiler/checker.ts

+26-10
Original file line numberDiff line numberDiff line change
@@ -2182,7 +2182,12 @@ namespace ts {
21822182

21832183
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration, dontResolveAlias: boolean): Symbol | undefined {
21842184
if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
2185-
return resolveExternalModuleSymbol(resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)));
2185+
const immediate = resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node));
2186+
const resolved = resolveExternalModuleSymbol(immediate);
2187+
if (!markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, immediate)) {
2188+
markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, resolved);
2189+
}
2190+
return resolved;
21862191
}
21872192
return getSymbolOfPartOfRightHandSideOfImportEquals(node.moduleReference, dontResolveAlias);
21882193
}
@@ -2278,7 +2283,9 @@ namespace ts {
22782283
else if (hasSyntheticDefault) {
22792284
// per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present
22802285
const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
2281-
if (!isTypeOnly) markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, resolved);
2286+
if (!isTypeOnly && !markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, moduleSymbol)) {
2287+
markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, resolved);
2288+
}
22822289
return resolved;
22832290
}
22842291
if (!isTypeOnly) markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, exportDefaultSymbol);
@@ -2289,8 +2296,11 @@ namespace ts {
22892296
function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol | undefined {
22902297
const moduleSpecifier = node.parent.parent.moduleSpecifier;
22912298
const isTypeOnly = markSymbolOfAliasDeclarationIfTypeOnly(node);
2292-
const resolved = resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false);
2293-
if (!isTypeOnly) markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, resolved);
2299+
const immediate = resolveExternalModuleName(node, moduleSpecifier);
2300+
const resolved = resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressUsageError*/ false);
2301+
if (!isTypeOnly && !markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, immediate)) {
2302+
markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, resolved);
2303+
}
22942304
return resolved;
22952305
}
22962306

@@ -2459,7 +2469,9 @@ namespace ts {
24592469

24602470
function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined {
24612471
const expression = (isExportAssignment(node) ? node.expression : node.right) as EntityNameExpression | ClassExpression;
2462-
return getTargetOfAliasLikeExpression(expression, dontResolveAlias);
2472+
const resolved = getTargetOfAliasLikeExpression(expression, dontResolveAlias);
2473+
markSymbolOfAliasDeclarationIfResolvesToTypeOnly(node, resolved);
2474+
return resolved;
24632475
}
24642476

24652477
function getTargetOfAliasLikeExpression(expression: Expression, dontResolveAlias: boolean) {
@@ -2556,14 +2568,18 @@ namespace ts {
25562568
return links.target;
25572569
}
25582570

2559-
function markSymbolOfAliasDeclarationIfResolvesToTypeOnly(aliasDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, resolvesToSymbol: Symbol | undefined) {
2560-
if (!aliasDeclaration || !resolvesToSymbol) return;
2571+
function markSymbolOfAliasDeclarationIfResolvesToTypeOnly(aliasDeclaration: Declaration | undefined, resolvesToSymbol: Symbol | undefined): boolean {
2572+
if (!aliasDeclaration || !resolvesToSymbol) return false;
25612573
const sourceSymbol = getSymbolOfNode(aliasDeclaration);
25622574
const links = getSymbolLinks(sourceSymbol);
25632575
if (links.typeOnlyDeclaration === undefined) {
2576+
resolvesToSymbol = resolvesToSymbol.exports?.get(InternalSymbolName.ExportEquals) ?? resolvesToSymbol;
25642577
const typeOnly = find(resolvesToSymbol.declarations, isTypeOnlyImportOrExportDeclaration);
2565-
links.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(resolvesToSymbol).typeOnlyDeclaration ?? false;
2578+
const decl = typeOnly ?? getSymbolLinks(resolvesToSymbol).typeOnlyDeclaration ?? false;
2579+
links.typeOnlyDeclaration = decl;
2580+
return !!decl;
25662581
}
2582+
return false;
25672583
}
25682584

25692585
function markSymbolOfAliasDeclarationIfTypeOnly(aliasDeclaration: TypeOnlyCompatibleAliasDeclaration): boolean {
@@ -2711,8 +2727,8 @@ namespace ts {
27112727
throw Debug.assertNever(name, "Unknown entity name kind.");
27122728
}
27132729
Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
2714-
if (isIdentifier(name) && symbol.flags & SymbolFlags.Alias) {
2715-
markSymbolOfAliasDeclarationIfResolvesToTypeOnly(getTypeOnlyCompatibleAliasDeclarationFromName(name), symbol);
2730+
if (isIdentifier(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) {
2731+
markSymbolOfAliasDeclarationIfResolvesToTypeOnly(getAliasDeclarationFromName(name), symbol);
27162732
}
27172733
return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol);
27182734
}

src/compiler/utilities.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -2766,13 +2766,14 @@ namespace ts {
27662766
node.kind === SyntaxKind.PropertyAssignment && isAliasableExpression((node as PropertyAssignment).initializer);
27672767
}
27682768

2769-
export function getTypeOnlyCompatibleAliasDeclarationFromName(node: Identifier): TypeOnlyCompatibleAliasDeclaration | undefined {
2769+
export function getAliasDeclarationFromName(node: Identifier): Declaration | undefined {
27702770
switch (node.parent.kind) {
27712771
case SyntaxKind.ImportClause:
27722772
case SyntaxKind.ImportSpecifier:
27732773
case SyntaxKind.NamespaceImport:
27742774
case SyntaxKind.ExportSpecifier:
2775-
return node.parent as TypeOnlyCompatibleAliasDeclaration;
2775+
case SyntaxKind.ExportAssignment:
2776+
return node.parent as Declaration;
27762777
}
27772778
}
27782779

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/d.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
2+
/e.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
3+
/f.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
4+
/g.ts(2,5): error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
5+
6+
7+
==== /a.ts (0 errors) ====
8+
export class A {}
9+
10+
==== /b.ts (0 errors) ====
11+
import type * as types from './a';
12+
export = types; // Error
13+
14+
==== /c.ts (0 errors) ====
15+
import * as types from './a';
16+
export = types;
17+
18+
==== /d.ts (1 errors) ====
19+
import types from './b';
20+
new types.A(); // Error
21+
~~~~~
22+
!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
23+
!!! related TS1376 /b.ts:1:13: 'types' was imported here.
24+
25+
==== /e.ts (1 errors) ====
26+
import types = require('./b');
27+
new types.A(); // Error
28+
~~~~~
29+
!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
30+
!!! related TS1376 /b.ts:1:13: 'types' was imported here.
31+
32+
==== /f.ts (1 errors) ====
33+
import * as types from './b';
34+
new types.A(); // Error
35+
~~~~~
36+
!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
37+
!!! related TS1376 /b.ts:1:13: 'types' was imported here.
38+
39+
==== /g.ts (1 errors) ====
40+
import type types from './c'
41+
new types.A(); // Error
42+
~~~~~
43+
!!! error TS1361: 'types' cannot be used as a value because it was imported using 'import type'.
44+
!!! related TS1376 /g.ts:1:8: 'types' was imported here.
45+
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/importEquals1.ts] ////
2+
3+
//// [a.ts]
4+
export class A {}
5+
6+
//// [b.ts]
7+
import type * as types from './a';
8+
export = types; // Error
9+
10+
//// [c.ts]
11+
import * as types from './a';
12+
export = types;
13+
14+
//// [d.ts]
15+
import types from './b';
16+
new types.A(); // Error
17+
18+
//// [e.ts]
19+
import types = require('./b');
20+
new types.A(); // Error
21+
22+
//// [f.ts]
23+
import * as types from './b';
24+
new types.A(); // Error
25+
26+
//// [g.ts]
27+
import type types from './c'
28+
new types.A(); // Error
29+
30+
31+
//// [a.js]
32+
"use strict";
33+
exports.__esModule = true;
34+
var A = /** @class */ (function () {
35+
function A() {
36+
}
37+
return A;
38+
}());
39+
exports.A = A;
40+
//// [b.js]
41+
"use strict";
42+
module.exports = types;
43+
//// [c.js]
44+
"use strict";
45+
var __importStar = (this && this.__importStar) || function (mod) {
46+
if (mod && mod.__esModule) return mod;
47+
var result = {};
48+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
49+
result["default"] = mod;
50+
return result;
51+
};
52+
var types = __importStar(require("./a"));
53+
module.exports = types;
54+
//// [d.js]
55+
"use strict";
56+
exports.__esModule = true;
57+
new types.A(); // Error
58+
//// [e.js]
59+
"use strict";
60+
exports.__esModule = true;
61+
new types.A(); // Error
62+
//// [f.js]
63+
"use strict";
64+
exports.__esModule = true;
65+
new types.A(); // Error
66+
//// [g.js]
67+
"use strict";
68+
exports.__esModule = true;
69+
new types.A(); // Error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
=== /a.ts ===
2+
export class A {}
3+
>A : Symbol(A, Decl(a.ts, 0, 0))
4+
5+
=== /b.ts ===
6+
import type * as types from './a';
7+
>types : Symbol(types, Decl(b.ts, 0, 11))
8+
9+
export = types; // Error
10+
>types : Symbol(types, Decl(b.ts, 0, 11))
11+
12+
=== /c.ts ===
13+
import * as types from './a';
14+
>types : Symbol(types, Decl(c.ts, 0, 6))
15+
16+
export = types;
17+
>types : Symbol(types, Decl(c.ts, 0, 6))
18+
19+
=== /d.ts ===
20+
import types from './b';
21+
>types : Symbol(types, Decl(d.ts, 0, 6))
22+
23+
new types.A(); // Error
24+
>types.A : Symbol(types.A, Decl(a.ts, 0, 0))
25+
>types : Symbol(types, Decl(d.ts, 0, 6))
26+
>A : Symbol(types.A, Decl(a.ts, 0, 0))
27+
28+
=== /e.ts ===
29+
import types = require('./b');
30+
>types : Symbol(types, Decl(e.ts, 0, 0))
31+
32+
new types.A(); // Error
33+
>types.A : Symbol(types.A, Decl(a.ts, 0, 0))
34+
>types : Symbol(types, Decl(e.ts, 0, 0))
35+
>A : Symbol(types.A, Decl(a.ts, 0, 0))
36+
37+
=== /f.ts ===
38+
import * as types from './b';
39+
>types : Symbol(types, Decl(f.ts, 0, 6))
40+
41+
new types.A(); // Error
42+
>types.A : Symbol(types.A, Decl(a.ts, 0, 0))
43+
>types : Symbol(types, Decl(f.ts, 0, 6))
44+
>A : Symbol(types.A, Decl(a.ts, 0, 0))
45+
46+
=== /g.ts ===
47+
import type types from './c'
48+
>types : Symbol(types, Decl(g.ts, 0, 6))
49+
50+
new types.A(); // Error
51+
>types.A : Symbol(types.A, Decl(a.ts, 0, 0))
52+
>types : Symbol(types, Decl(g.ts, 0, 6))
53+
>A : Symbol(types.A, Decl(a.ts, 0, 0))
54+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
=== /a.ts ===
2+
export class A {}
3+
>A : A
4+
5+
=== /b.ts ===
6+
import type * as types from './a';
7+
>types : typeof types
8+
9+
export = types; // Error
10+
>types : typeof types
11+
12+
=== /c.ts ===
13+
import * as types from './a';
14+
>types : typeof types
15+
16+
export = types;
17+
>types : typeof types
18+
19+
=== /d.ts ===
20+
import types from './b';
21+
>types : typeof types
22+
23+
new types.A(); // Error
24+
>new types.A() : types.A
25+
>types.A : typeof types.A
26+
>types : typeof types
27+
>A : typeof types.A
28+
29+
=== /e.ts ===
30+
import types = require('./b');
31+
>types : typeof types
32+
33+
new types.A(); // Error
34+
>new types.A() : types.A
35+
>types.A : typeof types.A
36+
>types : typeof types
37+
>A : typeof types.A
38+
39+
=== /f.ts ===
40+
import * as types from './b';
41+
>types : typeof types
42+
43+
new types.A(); // Error
44+
>new types.A() : types.A
45+
>types.A : typeof types.A
46+
>types : typeof types
47+
>A : typeof types.A
48+
49+
=== /g.ts ===
50+
import type types from './c'
51+
>types : any
52+
53+
new types.A(); // Error
54+
>new types.A() : types.A
55+
>types.A : typeof types.A
56+
>types : typeof types
57+
>A : typeof types.A
58+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/c.ts(2,7): error TS2339: Property 'A' does not exist on type 'typeof import("/a")'.
2+
3+
4+
==== /c.ts (1 errors) ====
5+
import a = require('./b');
6+
new a.A(); // Error
7+
~
8+
!!! error TS2339: Property 'A' does not exist on type 'typeof import("/a")'.
9+
10+
==== /a.ts (0 errors) ====
11+
class A {}
12+
export type { A }
13+
14+
==== /b.ts (0 errors) ====
15+
import * as a from './a';
16+
export = a;
17+
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/importEquals2.ts] ////
2+
3+
//// [a.ts]
4+
class A {}
5+
export type { A }
6+
7+
//// [b.ts]
8+
import * as a from './a';
9+
export = a;
10+
11+
//// [c.ts]
12+
import a = require('./b');
13+
new a.A(); // Error
14+
15+
16+
//// [a.js]
17+
"use strict";
18+
exports.__esModule = true;
19+
var A = /** @class */ (function () {
20+
function A() {
21+
}
22+
return A;
23+
}());
24+
//// [b.js]
25+
"use strict";
26+
var __importStar = (this && this.__importStar) || function (mod) {
27+
if (mod && mod.__esModule) return mod;
28+
var result = {};
29+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
30+
result["default"] = mod;
31+
return result;
32+
};
33+
var a = __importStar(require("./a"));
34+
module.exports = a;
35+
//// [c.js]
36+
"use strict";
37+
exports.__esModule = true;
38+
var a = require("./b");
39+
new a.A(); // Error

0 commit comments

Comments
 (0)