Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add--module node20#61805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
andrewbranch merged 4 commits intomicrosoft:mainfromandrewbranch:feature/node20
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from1 commit
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
PrevPrevious commit
NextNext commit
Support ESMmodule.exports named exports
  • Loading branch information
@andrewbranch
andrewbranch committedJun 2, 2025
commit218d141a0e38316e0dfc831b9e3bdd780ff74554
73 changes: 61 additions & 12 deletionssrc/compiler/checker.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3683,6 +3683,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
getExternalModuleRequireArgument(node) || getExternalModuleImportEqualsDeclarationExpression(node),
);
const resolved = resolveExternalModuleSymbol(immediate);
if (resolved && ModuleKind.Node20 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
const moduleExports = getExportOfModule(resolved, "module.exports" as __String, node, dontResolveAlias);
if (moduleExports) {
return moduleExports;
}
}
markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false);
return resolved;
}
Expand DownExpand Up@@ -3798,16 +3804,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function getTargetofModuleDefault(moduleSymbol: Symbol, node: ImportClause | ImportOrExportSpecifier, dontResolveAlias: boolean) {
const file = moduleSymbol.declarations?.find(isSourceFile);
const specifier = getModuleSpecifierForImportOrExport(node);
let exportDefaultSymbol: Symbol | undefined;
let exportModuleDotExportsSymbol: Symbol | undefined;
if (isShorthandAmbientModuleSymbol(moduleSymbol)) {
exportDefaultSymbol = moduleSymbol;
}
else if (
file && specifier &&
ModuleKind.Node20 <= moduleKind && moduleKind <= ModuleKind.NodeNext &&
getEmitSyntaxForModuleSpecifierExpression(specifier) === ModuleKind.CommonJS &&
host.getImpliedNodeFormatForEmit(file) === ModuleKind.ESNext &&
(exportModuleDotExportsSymbol = resolveExportByName(moduleSymbol, "module.exports" as __String, node, dontResolveAlias))
) {
// We have a transpiled default import where the `require` resolves to an ES module with a `module.exports` named
// export. If `esModuleInterop` is enabled, this will work:
//
// const dep_1 = __importDefault(require("./dep.mjs")); // wraps like { default: require("./dep.mjs") }
// dep_1.default; // require("./dep.mjs") -> the `module.exports` export value
//
// But without `esModuleInterop`, it will be broken:
//
// const dep_1 = require("./dep.mjs"); // the `module.exports` export value (could be primitive)
// dep_1.default; // `default` property access on the `module.exports` export value
//
// We could try to resolve the 'default' property in the latter case, but it's a mistake to run in this
// environment without `esModuleInterop`, so just error.
if (!getESModuleInterop(compilerOptions)) {
error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, symbolToString(moduleSymbol), "esModuleInterop");
return undefined;
}
markSymbolOfAliasDeclarationIfTypeOnly(node, exportModuleDotExportsSymbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ false);
return exportModuleDotExportsSymbol;
}
else {
exportDefaultSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, node, dontResolveAlias);
}

const file = moduleSymbol.declarations?.find(isSourceFile);
const specifier = getModuleSpecifierForImportOrExport(node);
if (!specifier) {
return exportDefaultSymbol;
}
Expand DownExpand Up@@ -4953,10 +4987,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

const referenceParent = referencingLocation.parent;
if (
(isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent)) ||
isImportCall(referenceParent)
) {
const namespaceImport = isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent);
if (namespaceImport || isImportCall(referenceParent)) {
const reference = isImportCall(referenceParent) ? referenceParent.arguments[0] : referenceParent.moduleSpecifier;
const type = getTypeOfSymbol(symbol);
const defaultOnlyType = getTypeWithSyntheticDefaultOnly(type, symbol, moduleSymbol!, reference);
Expand All@@ -4965,14 +4997,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

const targetFile = moduleSymbol?.declarations?.find(isSourceFile);
const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(getEmitSyntaxForModuleSpecifierExpression(reference), host.getImpliedNodeFormatForEmit(targetFile));
if (getESModuleInterop(compilerOptions) || isEsmCjsRef) {
let sigs = getSignaturesOfStructuredType(type, SignatureKind.Call);
if (!sigs || !sigs.length) {
sigs = getSignaturesOfStructuredType(type, SignatureKind.Construct);
const usageMode = getEmitSyntaxForModuleSpecifierExpression(reference);
let exportModuleDotExportsSymbol: Symbol | undefined;
if (
namespaceImport && targetFile &&
ModuleKind.Node20 <= moduleKind && moduleKind <= ModuleKind.NodeNext &&
usageMode === ModuleKind.CommonJS && host.getImpliedNodeFormatForEmit(targetFile) === ModuleKind.ESNext &&
(exportModuleDotExportsSymbol = resolveExportByName(symbol, "module.exports" as __String, namespaceImport, dontResolveAlias))
) {
if (!suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
error(referencingLocation, Diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, "esModuleInterop");
}
if (getESModuleInterop(compilerOptions) && hasSignatures(type)) {
return cloneTypeAsModuleType(exportModuleDotExportsSymbol, type, referenceParent);
}
return exportModuleDotExportsSymbol;
}

const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(usageMode, host.getImpliedNodeFormatForEmit(targetFile));
if (getESModuleInterop(compilerOptions) || isEsmCjsRef) {
if (
(sigs && sigs.length) ||
hasSignatures(type) ||
getPropertyOfType(type, InternalSymbolName.Default, /*skipObjectFunctionPropertyAugment*/ true) ||
isEsmCjsRef
) {
Expand All@@ -4987,6 +5032,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return symbol;
}

function hasSignatures(type: Type): boolean {
return some(getSignaturesOfStructuredType(type, SignatureKind.Call)) || some(getSignaturesOfStructuredType(type, SignatureKind.Construct));
}

/**
* Create a new symbol which has the module's type less the call and construct signatures
*/
Expand Down
24 changes: 24 additions & 0 deletionstests/baselines/reference/esmModuleExports1.errors.txt
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
/importer-cts.cts(10,10): error TS2614: Module '"./exporter.mjs"' has no exported member 'Oops'. Did you mean to use 'import Oops from "./exporter.mjs"' instead?


==== /importer-cjs.cjs (0 errors) ====
const Foo = require("./exporter.mjs");
new Foo();

==== /importer-cts.cts (1 errors) ====
import Foo = require("./exporter.mjs");
new Foo();

import Foo2 from "./exporter.mjs";
new Foo2();

import * as Foo3 from "./exporter.mjs";
new Foo3();

import { Oops } from "./exporter.mjs";
~~~~
!!! error TS2614: Module '"./exporter.mjs"' has no exported member 'Oops'. Did you mean to use 'import Oops from "./exporter.mjs"' instead?

==== /exporter.mts (0 errors) ====
export default class Foo {}
export { Foo as "module.exports" };
41 changes: 41 additions & 0 deletionstests/baselines/reference/esmModuleExports1.symbols
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
//// [tests/cases/conformance/node/esmModuleExports1.ts] ////

=== /importer-cjs.cjs ===
const Foo = require("./exporter.mjs");
>Foo : Symbol(Foo, Decl(importer-cjs.cjs, 0, 5))
>require : Symbol(require)
>"./exporter.mjs" : Symbol("/exporter", Decl(exporter.mts, 0, 0))

new Foo();
>Foo : Symbol(Foo, Decl(importer-cjs.cjs, 0, 5))

=== /importer-cts.cts ===
import Foo = require("./exporter.mjs");
>Foo : Symbol(Foo, Decl(importer-cts.cts, 0, 0))

new Foo();
>Foo : Symbol(Foo, Decl(importer-cts.cts, 0, 0))

import Foo2 from "./exporter.mjs";
>Foo2 : Symbol(Foo2, Decl(importer-cts.cts, 3, 6))

new Foo2();
>Foo2 : Symbol(Foo2, Decl(importer-cts.cts, 3, 6))

import * as Foo3 from "./exporter.mjs";
>Foo3 : Symbol(Foo3, Decl(importer-cts.cts, 6, 6))

new Foo3();
>Foo3 : Symbol(Foo3, Decl(importer-cts.cts, 6, 6))

import { Oops } from "./exporter.mjs";
>Oops : Symbol(Oops, Decl(importer-cts.cts, 9, 8))

=== /exporter.mts ===
export default class Foo {}
>Foo : Symbol(Foo, Decl(exporter.mts, 0, 0))

export { Foo as "module.exports" };
>Foo : Symbol(Foo, Decl(exporter.mts, 0, 0))
>"module.exports" : Symbol("module.exports", Decl(exporter.mts, 1, 8))

65 changes: 65 additions & 0 deletionstests/baselines/reference/esmModuleExports1.types
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
//// [tests/cases/conformance/node/esmModuleExports1.ts] ////

=== /importer-cjs.cjs ===
const Foo = require("./exporter.mjs");
>Foo : typeof Foo
> : ^^^^^^^^^^
>require("./exporter.mjs") : typeof import("/exporter", { with: { "resolution-mode": "import" } })
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>require : any
> : ^^^
>"./exporter.mjs" : "./exporter.mjs"
> : ^^^^^^^^^^^^^^^^

new Foo();
>new Foo() : Foo
> : ^^^
>Foo : typeof Foo
> : ^^^^^^^^^^

=== /importer-cts.cts ===
import Foo = require("./exporter.mjs");
>Foo : typeof Foo
> : ^^^^^^^^^^

new Foo();
>new Foo() : Foo
> : ^^^
>Foo : typeof Foo
> : ^^^^^^^^^^

import Foo2 from "./exporter.mjs";
>Foo2 : typeof Foo
> : ^^^^^^^^^^

new Foo2();
>new Foo2() : Foo
> : ^^^
>Foo2 : typeof Foo
> : ^^^^^^^^^^

import * as Foo3 from "./exporter.mjs";
>Foo3 : typeof Foo
> : ^^^^^^^^^^

new Foo3();
>new Foo3() : Foo
> : ^^^
>Foo3 : typeof Foo
> : ^^^^^^^^^^

import { Oops } from "./exporter.mjs";
>Oops : any
> : ^^^

=== /exporter.mts ===
export default class Foo {}
>Foo : Foo
> : ^^^

export { Foo as "module.exports" };
>Foo : typeof Foo
> : ^^^^^^^^^^
>"module.exports" : typeof Foo
> : ^^^^^^^^^^

View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
/importer-cjs.cjs(2,5): error TS2351: This expression is not constructable.
Type 'String' has no construct signatures.
/importer-cts.cts(2,5): error TS2351: This expression is not constructable.
Type 'String' has no construct signatures.
/importer-cts.cts(4,8): error TS1259: Module '"/exporter"' can only be default-imported using the 'esModuleInterop' flag
/importer-cts.cts(8,5): error TS2351: This expression is not constructable.
Type 'String' has no construct signatures.
/importer-cts.cts(10,10): error TS2614: Module '"./exporter.mjs"' has no exported member 'Oops'. Did you mean to use 'import Oops from "./exporter.mjs"' instead?


==== /importer-cjs.cjs (1 errors) ====
const Foo = require("./exporter.mjs");
new Foo();
~~~
!!! error TS2351: This expression is not constructable.
!!! error TS2351: Type 'String' has no construct signatures.

==== /importer-cts.cts (4 errors) ====
import Foo = require("./exporter.mjs");
new Foo();
~~~
!!! error TS2351: This expression is not constructable.
!!! error TS2351: Type 'String' has no construct signatures.

import Foo2 from "./exporter.mjs";
~~~~
!!! error TS1259: Module '"/exporter"' can only be default-imported using the 'esModuleInterop' flag
new Foo2();

import * as Foo3 from "./exporter.mjs";
new Foo3();
~~~~
!!! error TS2351: This expression is not constructable.
!!! error TS2351: Type 'String' has no construct signatures.

import { Oops } from "./exporter.mjs";
~~~~
!!! error TS2614: Module '"./exporter.mjs"' has no exported member 'Oops'. Did you mean to use 'import Oops from "./exporter.mjs"' instead?

==== /exporter.mts (0 errors) ====
export default class Foo {}
const oops = "oops";
export { oops as "module.exports" };
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
//// [tests/cases/conformance/node/esmModuleExports2.ts] ////

=== /importer-cjs.cjs ===
const Foo = require("./exporter.mjs");
>Foo : Symbol(Foo, Decl(importer-cjs.cjs, 0, 5))
>require : Symbol(require)
>"./exporter.mjs" : Symbol("/exporter", Decl(exporter.mts, 0, 0))

new Foo();
>Foo : Symbol(Foo, Decl(importer-cjs.cjs, 0, 5))

=== /importer-cts.cts ===
import Foo = require("./exporter.mjs");
>Foo : Symbol(Foo, Decl(importer-cts.cts, 0, 0))

new Foo();
>Foo : Symbol(Foo, Decl(importer-cts.cts, 0, 0))

import Foo2 from "./exporter.mjs";
>Foo2 : Symbol(Foo2, Decl(importer-cts.cts, 3, 6))

new Foo2();
>Foo2 : Symbol(Foo2, Decl(importer-cts.cts, 3, 6))

import * as Foo3 from "./exporter.mjs";
>Foo3 : Symbol(Foo3, Decl(importer-cts.cts, 6, 6))

new Foo3();
>Foo3 : Symbol(Foo3, Decl(importer-cts.cts, 6, 6))

import { Oops } from "./exporter.mjs";
>Oops : Symbol(Oops, Decl(importer-cts.cts, 9, 8))

=== /exporter.mts ===
export default class Foo {}
>Foo : Symbol(Foo, Decl(exporter.mts, 0, 0))

const oops = "oops";
>oops : Symbol(oops, Decl(exporter.mts, 1, 5))

export { oops as "module.exports" };
>oops : Symbol(oops, Decl(exporter.mts, 1, 5))
>"module.exports" : Symbol("module.exports", Decl(exporter.mts, 2, 8))

Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp