Co-authored-by: eli lichtblau <elilichtblau@elis-MacBook-Pro.local>
Co-authored-by: Andrew Branch <andrew@wheream.io>
This commit is contained in:
EliLichtblau 2023-11-20 13:19:57 -05:00 committed by GitHub
parent c10edfbc8d
commit 9063d7b41d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 353 additions and 5 deletions

View File

@ -45846,12 +45846,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
@ -45870,6 +45871,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
idText(id),
);
}
if (!isIllegalExportDefaultInCJS && getIsolatedModules(compilerOptions) && !(sym.flags & SymbolFlags.Value)) {
if (
sym.flags & SymbolFlags.Alias
&& resolveAlias(sym) !== unknownSymbol
&& 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
@ -47558,7 +47597,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;

View File

@ -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",

View File

@ -12,4 +12,11 @@
~
!!! 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;

View File

@ -9,6 +9,13 @@ 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";
@ -22,3 +29,9 @@ var A = /** @class */ (function () {
"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 });

View File

@ -18,3 +18,17 @@ declare const a: A;
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))

View File

@ -18,3 +18,17 @@ 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

View File

@ -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.

View File

@ -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 });

View File

@ -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))

View File

@ -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

View File

@ -41,7 +41,6 @@ exports.A = A;
//// [b.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = types;
//// [c.js]
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {

View File

@ -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) {

View File

@ -0,0 +1,36 @@
/test1.ts(1,10): error TS2865: Import 'T' conflicts with local value, so must be declared with a type-only import when 'isolatedModules' is enabled.
/test2.ts(1,10): error TS2440: Import declaration conflicts with local declaration of 'T'.
/test2.ts(3,16): error TS1292: 'T' resolves to a type and must be marked type-only in this file before re-exporting when 'isolatedModules' is enabled. Consider using 'export type { T as default }'.
/test3.ts(2,16): error TS1292: 'T' resolves to a type and must be marked type-only in this file before re-exporting when 'isolatedModules' is enabled. Consider using 'export type { T as default }'.
==== /type.ts (0 errors) ====
export type T = number;
==== /test1.ts (1 errors) ====
import { T } from "./type";
~
!!! error TS2865: Import 'T' conflicts with local value, so must be declared with a type-only import when 'isolatedModules' is enabled.
const T = 0; // Error as of #56354
export default T; // Ok
==== /test2.ts (2 errors) ====
import { T } from "./type";
~
!!! error TS2440: Import declaration conflicts with local declaration of 'T'.
type T = number; // Merge error
export default T; // Transpiler could assume the alias resolves to a value?
~
!!! error TS1292: 'T' resolves to a type and must be marked type-only in this file before re-exporting when 'isolatedModules' is enabled. Consider using 'export type { T as default }'.
==== /test3.ts (1 errors) ====
import { T } from "./type";
export default T; // Error
~
!!! error TS1292: 'T' resolves to a type and must be marked type-only in this file before re-exporting when 'isolatedModules' is enabled. Consider using 'export type { T as default }'.
==== /test4.ts (0 errors) ====
// @ts-expect-error
import unresolved from "./doesntexist";
export default unresolved;

View File

@ -0,0 +1,45 @@
//// [tests/cases/compiler/isolatedModulesExportDeclarationType.ts] ////
//// [type.ts]
export type T = number;
//// [test1.ts]
import { T } from "./type";
const T = 0; // Error as of #56354
export default T; // Ok
//// [test2.ts]
import { T } from "./type";
type T = number; // Merge error
export default T; // Transpiler could assume the alias resolves to a value?
//// [test3.ts]
import { T } from "./type";
export default T; // Error
//// [test4.ts]
// @ts-expect-error
import unresolved from "./doesntexist";
export default unresolved;
//// [type.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [test1.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var T = 0; // Error as of #56354
exports.default = T; // Ok
//// [test2.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [test3.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [test4.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// @ts-expect-error
var doesntexist_1 = require("./doesntexist");
exports.default = doesntexist_1.default;

View File

@ -0,0 +1,24 @@
// @isolatedModules: true
// @noTypesAndSymbols: true
// @Filename: /type.ts
export type T = number;
// @Filename: /test1.ts
import { T } from "./type";
const T = 0; // Error as of #56354
export default T; // Ok
// @Filename: /test2.ts
import { T } from "./type";
type T = number; // Merge error
export default T; // Transpiler could assume the alias resolves to a value?
// @Filename: /test3.ts
import { T } from "./type";
export default T; // Error
// @Filename: /test4.ts
// @ts-expect-error
import unresolved from "./doesntexist";
export default unresolved;

View File

@ -1,3 +1,6 @@
// @module: commonjs
// @isolatedModules: false, true
// @Filename: /a.ts
class A {}
export type { A };
@ -6,3 +9,11 @@ export type { A };
import { A } from './a';
declare const a: A;
new A();
// @Filename: /c.ts
import type { A } from './a';
export = A;
// @Filename: /d.ts
import { A } from './a';
export = A;