Repository navigation
Closed
Labels
Possible ImprovementThe current behavior isn't wrong, but it's possible to see that it might be better in some casesThe current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone
Description
π Search Terms
"commonjs", "import", "type", "module"
β Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
β Suggestion
Proposal: Allow importing pure types from .mts files from a CommonJS file.
The current behavior generates an unnecessary / incorrect error since no require will be emitted.
Please note, future versions of Node will support requiring an ESM module if a there is not a top level await. See:
π Motivating Example
src/code.cts
import type { EntityId, Entity, User } from './models.mjs';
export function userName(user: User): string {
return user.name;
}src/models.mts
export type EntityId = string;
export interface Entity {
id: EntityId;
}
export interface User extends Entity {
name: string;
}π» Use Cases
- What do you want to use this for?
In mixed code bases (especially as they transition from CommonJS to ESM) it is often necessary export the types from a module that are used in CommonJS files. - What shortcomings exist with current approaches?
All shared types must be declared in CommonJS files or inferred usingAwaited. - What workarounds are you using in the meantime?
Declaring shared types in CommonJS files.
Metadata
Metadata
Assignees
Labels
Possible ImprovementThe current behavior isn't wrong, but it's possible to see that it might be better in some casesThe current behavior isn't wrong, but it's possible to see that it might be better in some cases

Activity
RyanCavanaugh commentedon Apr 15, 2024
Duplicate #52529edit: maybe?RyanCavanaugh commentedon Apr 15, 2024
Andrew Branch (@andrewbranch) points out that the concerns in the linked issue are specific to resolution hitting different targets in upstream packages due to revisions in their package jsons, but this argument doesn't apply at all to local relative paths
andrewbranch commentedon Apr 15, 2024
The currently intended behavior is that youβre supposed to silence this error by adding
with { "resolution-mode": "import" }to assert that youβre doing what youβre doing on purpose. At minimum, we need to update this error message to suggest that workaround, but I was finding it hard to construct a message that adequately explains whatβs wrong with this code, since Iβm still somewhat skeptical that thereβs anything wrong with this code.jakebailey commentedon Apr 15, 2024
I'm confused; isn't the context of this issue nodejs/node#51977, such that when that's "final", we need to have a new module resolution mode which re-allows
require(ESM)? And that this issue isn't about anything else?(Hm, maybe not, as the above was just a "side point" of sorts...)
Jason3S commentedon Apr 15, 2024
Andrew Branch (@andrewbranch),
This solves the my main issue. I did search for this, but wasn't able to figure it out based upon #53656. I was also trying to use
verbatimModuleSyntax, but that doesn't work withCommonJSfiles.I completely missed typescriptlang.org Stable Support
resolution-modein Import Types. I knew aboutwith { type: "json" }.By the way, the "value" of "resolution-mode" doesn't seem to matter for local files.
This works fine.
src/code.ctsWhich leads to the question of why
resolution-modeis necessary for local files.Jake Bailey (@jakebailey),
It is a "side point", I was using it as part of the argument that importing ESM files from a CJS file is necessary to support. Given that, it would also preclude the need for
with { "resolution-mode": "import" }andrewbranch commentedon Apr 15, 2024
Yeah, if that lands without a flag, there will be a new module mode /
nodenextwill be updated to support it without error. Thereβs nothing to do on that front yet.RyanCavanaugh commentedon Apr 17, 2024
We should at least update the error message to suggest the resolution mode assertion
Jason3S commentedon May 14, 2024
It looks like Node 22 includes
require('./file.mjs')support: Support require()ing synchronous ESM graphs.andrewbranch commentedon May 14, 2024
Under an experimental flag.
nodenextwonβt be updated until it lands unflagged.JounQin commentedon Apr 12, 2025
Andrew Branch (@andrewbranch) Can we support import
.d.mtsfrom.d.ctsfirst?Workaround:
I was thinking to workaround this with:
But
tscfailed atDebug.assert(isExpressionNode(node)):Details
Related
lib/index.d.ts: https://app.unpkg.com/[email protected]/files/lib/index.d.tsindex.d.cts: https://app.unpkg.com/[email protected]/files/index.d.ctsEdit:
The failing workaround seems related to
import * as pluginImportX from 'eslint-plugin-import-x',import pluginImportX from 'eslint-plugin-import-x'works fine with:And even:
andrewbranch commentedon Apr 14, 2025
JounQin (@JounQin) we definitely shouldn't be crashing like that... would you mind posting that to a new issue with repro steps? Thanks!
JounQin commentedon Apr 15, 2025
Andrew Branch (@andrewbranch) Here we go: https://github.com/eslinter/eslint-config-standard/tree/repro/tsc