Skip to content

Commit 9063d7b

Browse files
EliLichtblaueli lichtblauandrewbranch
authored
Error on export default of type: issue #55087 (#55097)
Co-authored-by: eli lichtblau <[email protected]> Co-authored-by: Andrew Branch <[email protected]>
1 parent c10edfb commit 9063d7b

16 files changed

+353
-5
lines changed

src/compiler/checker.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45846,12 +45846,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4584645846
const id = node.expression as Identifier;
4584745847
const sym = getExportSymbolOfValueSymbolIfExported(resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node));
4584845848
if (sym) {
45849+
const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value);
4584945850
markAliasReferenced(sym, id);
4585045851
// If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`)
4585145852
if (getSymbolFlags(sym) & SymbolFlags.Value) {
4585245853
// However if it is a value, we need to check it's being used correctly
4585345854
checkExpressionCached(id);
45854-
if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax && getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value)) {
45855+
if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax && typeOnlyDeclaration) {
4585545856
error(
4585645857
id,
4585745858
node.isExportEquals
@@ -45870,6 +45871,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4587045871
idText(id),
4587145872
);
4587245873
}
45874+
45875+
if (!isIllegalExportDefaultInCJS && getIsolatedModules(compilerOptions) && !(sym.flags & SymbolFlags.Value)) {
45876+
if (
45877+
sym.flags & SymbolFlags.Alias
45878+
&& resolveAlias(sym) !== unknownSymbol
45879+
&& getSymbolFlags(sym, /*excludeTypeOnlyMeanings*/ false, /*excludeLocalMeanings*/ true) & SymbolFlags.Type
45880+
&& (!typeOnlyDeclaration || getSourceFileOfNode(typeOnlyDeclaration) !== getSourceFileOfNode(node))
45881+
) {
45882+
// import { SomeType } from "./someModule";
45883+
// export default SomeType; OR
45884+
// export = SomeType;
45885+
error(
45886+
id,
45887+
node.isExportEquals ?
45888+
Diagnostics._0_resolves_to_a_type_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_import_type_where_0_is_imported
45889+
: Diagnostics._0_resolves_to_a_type_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_export_type_0_as_default,
45890+
idText(id),
45891+
isolatedModulesLikeFlagName,
45892+
);
45893+
}
45894+
else if (typeOnlyDeclaration && getSourceFileOfNode(typeOnlyDeclaration) !== getSourceFileOfNode(node)) {
45895+
// import { SomeTypeOnlyValue } from "./someModule";
45896+
// export default SomeTypeOnlyValue; OR
45897+
// export = SomeTypeOnlyValue;
45898+
addTypeOnlyDeclarationRelatedInfo(
45899+
error(
45900+
id,
45901+
node.isExportEquals ?
45902+
Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_import_type_where_0_is_imported
45903+
: Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_marked_type_only_in_this_file_before_re_exporting_when_1_is_enabled_Consider_using_export_type_0_as_default,
45904+
idText(id),
45905+
isolatedModulesLikeFlagName,
45906+
),
45907+
typeOnlyDeclaration,
45908+
idText(id),
45909+
);
45910+
}
45911+
}
4587345912
}
4587445913
else {
4587545914
checkExpressionCached(id); // doesn't resolve, check as expression to mark as error
@@ -47558,7 +47597,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4755847597
);
4755947598
case SyntaxKind.ExportAssignment:
4756047599
return (node as ExportAssignment).expression && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier ?
47561-
isAliasResolvedToValue(getSymbolOfDeclaration(node as ExportAssignment)) :
47600+
isAliasResolvedToValue(getSymbolOfDeclaration(node as ExportAssignment), /*excludeTypeOnlyValues*/ true) :
4756247601
true;
4756347602
}
4756447603
return false;

src/compiler/diagnosticMessages.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,22 @@
951951
"category": "Error",
952952
"code": 1288
953953
},
954+
"'{0}' resolves to a type-only declaration and must be marked type-only in this file before re-exporting when '{1}' is enabled. Consider using 'import type' where '{0}' is imported.": {
955+
"category": "Error",
956+
"code": 1289
957+
},
958+
"'{0}' resolves to a type-only declaration and must be marked type-only in this file before re-exporting when '{1}' is enabled. Consider using 'export type { {0} as default }'.": {
959+
"category": "Error",
960+
"code": 1290
961+
},
962+
"'{0}' resolves to a type and must be marked type-only in this file before re-exporting when '{1}' is enabled. Consider using 'import type' where '{0}' is imported.": {
963+
"category": "Error",
964+
"code": 1291
965+
},
966+
"'{0}' resolves to a type and must be marked type-only in this file before re-exporting when '{1}' is enabled. Consider using 'export type { {0} as default }'.": {
967+
"category": "Error",
968+
"code": 1292
969+
},
954970

955971
"'with' statements are not allowed in an async function block.": {
956972
"category": "Error",

tests/baselines/reference/exportDeclaration.errors.txt renamed to tests/baselines/reference/exportDeclaration(isolatedmodules=false).errors.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,11 @@
1212
~
1313
!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
1414
!!! related TS1377 /a.ts:2:15: 'A' was exported here.
15-
15+
16+
==== /c.ts (0 errors) ====
17+
import type { A } from './a';
18+
export = A;
19+
20+
==== /d.ts (0 errors) ====
21+
import { A } from './a';
22+
export = A;

tests/baselines/reference/exportDeclaration.js renamed to tests/baselines/reference/exportDeclaration(isolatedmodules=false).js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import { A } from './a';
99
declare const a: A;
1010
new A();
1111

12+
//// [c.ts]
13+
import type { A } from './a';
14+
export = A;
15+
16+
//// [d.ts]
17+
import { A } from './a';
18+
export = A;
1219

1320
//// [a.js]
1421
"use strict";
@@ -22,3 +29,9 @@ var A = /** @class */ (function () {
2229
"use strict";
2330
Object.defineProperty(exports, "__esModule", { value: true });
2431
new A();
32+
//// [c.js]
33+
"use strict";
34+
Object.defineProperty(exports, "__esModule", { value: true });
35+
//// [d.js]
36+
"use strict";
37+
Object.defineProperty(exports, "__esModule", { value: true });

tests/baselines/reference/exportDeclaration.symbols renamed to tests/baselines/reference/exportDeclaration(isolatedmodules=false).symbols

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,17 @@ declare const a: A;
1818
new A();
1919
>A : Symbol(A, Decl(b.ts, 0, 8))
2020

21+
=== /c.ts ===
22+
import type { A } from './a';
23+
>A : Symbol(A, Decl(c.ts, 0, 13))
24+
25+
export = A;
26+
>A : Symbol(A, Decl(c.ts, 0, 13))
27+
28+
=== /d.ts ===
29+
import { A } from './a';
30+
>A : Symbol(A, Decl(d.ts, 0, 8))
31+
32+
export = A;
33+
>A : Symbol(A, Decl(d.ts, 0, 8))
34+

tests/baselines/reference/exportDeclaration.types renamed to tests/baselines/reference/exportDeclaration(isolatedmodules=false).types

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,17 @@ new A();
1818
>new A() : A
1919
>A : typeof A
2020

21+
=== /c.ts ===
22+
import type { A } from './a';
23+
>A : A
24+
25+
export = A;
26+
>A : A
27+
28+
=== /d.ts ===
29+
import { A } from './a';
30+
>A : typeof A
31+
32+
export = A;
33+
>A : A
34+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/b.ts(3,5): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
2+
/d.ts(2,10): error TS1291: 'A' resolves to a type and must be marked type-only in this file before re-exporting when 'isolatedModules' is enabled. Consider using 'import type' where 'A' is imported.
3+
4+
5+
==== /a.ts (0 errors) ====
6+
class A {}
7+
export type { A };
8+
9+
==== /b.ts (1 errors) ====
10+
import { A } from './a';
11+
declare const a: A;
12+
new A();
13+
~
14+
!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
15+
!!! related TS1377 /a.ts:2:15: 'A' was exported here.
16+
17+
==== /c.ts (0 errors) ====
18+
import type { A } from './a';
19+
export = A;
20+
21+
==== /d.ts (1 errors) ====
22+
import { A } from './a';
23+
export = A;
24+
~
25+
!!! error TS1291: 'A' resolves to a type and must be marked type-only in this file before re-exporting when 'isolatedModules' is enabled. Consider using 'import type' where 'A' is imported.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////
2+
3+
//// [a.ts]
4+
class A {}
5+
export type { A };
6+
7+
//// [b.ts]
8+
import { A } from './a';
9+
declare const a: A;
10+
new A();
11+
12+
//// [c.ts]
13+
import type { A } from './a';
14+
export = A;
15+
16+
//// [d.ts]
17+
import { A } from './a';
18+
export = A;
19+
20+
//// [a.js]
21+
"use strict";
22+
Object.defineProperty(exports, "__esModule", { value: true });
23+
var A = /** @class */ (function () {
24+
function A() {
25+
}
26+
return A;
27+
}());
28+
//// [b.js]
29+
"use strict";
30+
Object.defineProperty(exports, "__esModule", { value: true });
31+
new A();
32+
//// [c.js]
33+
"use strict";
34+
Object.defineProperty(exports, "__esModule", { value: true });
35+
//// [d.js]
36+
"use strict";
37+
Object.defineProperty(exports, "__esModule", { value: true });
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////
2+
3+
=== /a.ts ===
4+
class A {}
5+
>A : Symbol(A, Decl(a.ts, 0, 0))
6+
7+
export type { A };
8+
>A : Symbol(A, Decl(a.ts, 1, 13))
9+
10+
=== /b.ts ===
11+
import { A } from './a';
12+
>A : Symbol(A, Decl(b.ts, 0, 8))
13+
14+
declare const a: A;
15+
>a : Symbol(a, Decl(b.ts, 1, 13))
16+
>A : Symbol(A, Decl(b.ts, 0, 8))
17+
18+
new A();
19+
>A : Symbol(A, Decl(b.ts, 0, 8))
20+
21+
=== /c.ts ===
22+
import type { A } from './a';
23+
>A : Symbol(A, Decl(c.ts, 0, 13))
24+
25+
export = A;
26+
>A : Symbol(A, Decl(c.ts, 0, 13))
27+
28+
=== /d.ts ===
29+
import { A } from './a';
30+
>A : Symbol(A, Decl(d.ts, 0, 8))
31+
32+
export = A;
33+
>A : Symbol(A, Decl(d.ts, 0, 8))
34+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////
2+
3+
=== /a.ts ===
4+
class A {}
5+
>A : A
6+
7+
export type { A };
8+
>A : A
9+
10+
=== /b.ts ===
11+
import { A } from './a';
12+
>A : typeof A
13+
14+
declare const a: A;
15+
>a : A
16+
17+
new A();
18+
>new A() : A
19+
>A : typeof A
20+
21+
=== /c.ts ===
22+
import type { A } from './a';
23+
>A : A
24+
25+
export = A;
26+
>A : A
27+
28+
=== /d.ts ===
29+
import { A } from './a';
30+
>A : typeof A
31+
32+
export = A;
33+
>A : A
34+

0 commit comments

Comments
 (0)