Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45835,12 +45835,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const id = node.expression as Identifier;
const sym = getExportSymbolOfValueSymbolIfExported(resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node));
if (sym) {
const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value);
markAliasReferenced(sym, id);
// If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`)
if (getSymbolFlags(sym) & SymbolFlags.Value) {
// However if it is a value, we need to check it's being used correctly
checkExpressionCached(id);
if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax && getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value)) {
if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax && typeOnlyDeclaration) {
error(
id,
node.isExportEquals
Expand All @@ -45859,6 +45860,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
idText(id),
);
}

if (!isIllegalExportDefaultInCJS && getIsolatedModules(compilerOptions) && !(sym.flags & SymbolFlags.Value)) {
if (
sym.flags & SymbolFlags.Alias
&& getSymbolFlags(sym, /*excludeTypeOnlyMeanings*/ false, /*excludeLocalMeanings*/ true) & SymbolFlags.Type
&& (!typeOnlyDeclaration || getSourceFileOfNode(typeOnlyDeclaration) !== getSourceFileOfNode(node))
) {
// import { SomeType } from "./someModule";
// export default SomeType; OR
// export = SomeType;
error(
id,
node.isExportEquals ?
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
: 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,
idText(id),
isolatedModulesLikeFlagName,
);
}
else if (typeOnlyDeclaration && getSourceFileOfNode(typeOnlyDeclaration) !== getSourceFileOfNode(node)) {
// import { SomeTypeOnlyValue } from "./someModule";
// export default SomeTypeOnlyValue; OR
// export = SomeTypeOnlyValue;
addTypeOnlyDeclarationRelatedInfo(
error(
id,
node.isExportEquals ?
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
: 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,
idText(id),
isolatedModulesLikeFlagName,
),
typeOnlyDeclaration,
idText(id),
);
}
}
}
else {
checkExpressionCached(id); // doesn't resolve, check as expression to mark as error
Expand Down Expand Up @@ -47547,7 +47585,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
case SyntaxKind.ExportAssignment:
return (node as ExportAssignment).expression && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier ?
isAliasResolvedToValue(getSymbolOfDeclaration(node as ExportAssignment)) :
isAliasResolvedToValue(getSymbolOfDeclaration(node as ExportAssignment), /*excludeTypeOnlyValues*/ true) :
true;
}
return false;
Expand Down
16 changes: 16 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,22 @@
"category": "Error",
"code": 1288
},
"'{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.": {
"category": "Error",
"code": 1289
},
"'{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 }'.": {
"category": "Error",
"code": 1290
},
"'{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.": {
"category": "Error",
"code": 1291
},
"'{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 }'.": {
"category": "Error",
"code": 1292
},

"'with' statements are not allowed in an async function block.": {
"category": "Error",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/b.ts(3,5): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.


==== /a.ts (0 errors) ====
class A {}
export type { A };

==== /b.ts (1 errors) ====
import { A } from './a';
declare const a: A;
new A();
~
!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
!!! related TS1377 /a.ts:2:15: 'A' was exported here.

==== /c.ts (0 errors) ====
import type { A } from './a';
export = A;

==== /d.ts (0 errors) ====
import { A } from './a';
export = A;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////

//// [a.ts]
class A {}
export type { A };

//// [b.ts]
import { A } from './a';
declare const a: A;
new A();

//// [c.ts]
import type { A } from './a';
export = A;

//// [d.ts]
import { A } from './a';
export = A;

//// [a.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var A = /** @class */ (function () {
function A() {
}
return A;
}());
//// [b.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
new A();
//// [c.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [d.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////

=== /a.ts ===
class A {}
>A : Symbol(A, Decl(a.ts, 0, 0))

export type { A };
>A : Symbol(A, Decl(a.ts, 1, 13))

=== /b.ts ===
import { A } from './a';
>A : Symbol(A, Decl(b.ts, 0, 8))

declare const a: A;
>a : Symbol(a, Decl(b.ts, 1, 13))
>A : Symbol(A, Decl(b.ts, 0, 8))

new A();
>A : Symbol(A, Decl(b.ts, 0, 8))

=== /c.ts ===
import type { A } from './a';
>A : Symbol(A, Decl(c.ts, 0, 13))

export = A;
>A : Symbol(A, Decl(c.ts, 0, 13))

=== /d.ts ===
import { A } from './a';
>A : Symbol(A, Decl(d.ts, 0, 8))

export = A;
>A : Symbol(A, Decl(d.ts, 0, 8))

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////

=== /a.ts ===
class A {}
>A : A

export type { A };
>A : A

=== /b.ts ===
import { A } from './a';
>A : typeof A

declare const a: A;
>a : A

new A();
>new A() : A
>A : typeof A

=== /c.ts ===
import type { A } from './a';
>A : A

export = A;
>A : A

=== /d.ts ===
import { A } from './a';
>A : typeof A

export = A;
>A : A

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/b.ts(3,5): error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
/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.


==== /a.ts (0 errors) ====
class A {}
export type { A };

==== /b.ts (1 errors) ====
import { A } from './a';
declare const a: A;
new A();
~
!!! error TS1362: 'A' cannot be used as a value because it was exported using 'export type'.
!!! related TS1377 /a.ts:2:15: 'A' was exported here.

==== /c.ts (0 errors) ====
import type { A } from './a';
export = A;

==== /d.ts (1 errors) ====
import { A } from './a';
export = A;
~
!!! 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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////

//// [a.ts]
class A {}
export type { A };

//// [b.ts]
import { A } from './a';
declare const a: A;
new A();

//// [c.ts]
import type { A } from './a';
export = A;

//// [d.ts]
import { A } from './a';
export = A;

//// [a.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var A = /** @class */ (function () {
function A() {
}
return A;
}());
//// [b.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
new A();
//// [c.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [d.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////

=== /a.ts ===
class A {}
>A : Symbol(A, Decl(a.ts, 0, 0))

export type { A };
>A : Symbol(A, Decl(a.ts, 1, 13))

=== /b.ts ===
import { A } from './a';
>A : Symbol(A, Decl(b.ts, 0, 8))

declare const a: A;
>a : Symbol(a, Decl(b.ts, 1, 13))
>A : Symbol(A, Decl(b.ts, 0, 8))

new A();
>A : Symbol(A, Decl(b.ts, 0, 8))

=== /c.ts ===
import type { A } from './a';
>A : Symbol(A, Decl(c.ts, 0, 13))

export = A;
>A : Symbol(A, Decl(c.ts, 0, 13))

=== /d.ts ===
import { A } from './a';
>A : Symbol(A, Decl(d.ts, 0, 8))

export = A;
>A : Symbol(A, Decl(d.ts, 0, 8))

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts] ////

=== /a.ts ===
class A {}
>A : A

export type { A };
>A : A

=== /b.ts ===
import { A } from './a';
>A : typeof A

declare const a: A;
>a : A

new A();
>new A() : A
>A : typeof A

=== /c.ts ===
import type { A } from './a';
>A : A

export = A;
>A : A

=== /d.ts ===
import { A } from './a';
>A : typeof A

export = A;
>A : A

1 change: 0 additions & 1 deletion tests/baselines/reference/exportDefault.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ exports.A = A;
//// [b.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = types;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeppp

//// [c.js]
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/importEquals1.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var A = /** @class */ (function () {
exports.A = A;
//// [b.js]
"use strict";
module.exports = types;
Object.defineProperty(exports, "__esModule", { value: true });
//// [c.js]
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
Expand Down
Loading