Skip to content

[5.5 beta] package.json "type" lookup in non-Node.js module is unexpected #58663

Description

🔎 Search Terms

moduleDetection force legacy

🕗 Version & Regression Information

  • This changed in version 5.5-beta

⏯ Playground Link

No response

💻 Code

package.json:

{
  "name": "ts-test",
  "version": "1.0.0",
  "description": "",
  "type": "commonjs",
  "devDependencies": {
    "typescript": "^5.5.0-beta"
  }
}

tsconfig.json:

{
  "include": ["src/index.ts"],
  "compilerOptions": {
    "module": "Preserve",
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "emitDeclarationOnly": true,
    "declaration": true,
    "declarationDir": "./dts"
  }
}

src/index.ts:

export let a = 1;

🙁 Actual behavior

src/index.ts:1:1 - error TS1287: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.

1 export let a = 1;

🙂 Expected behavior

Given that I'm using "moduleDetection": "force", that file is an ES module (regardless of what package.json#type says) and thus I shouldn't see that error. This was the behavior in 5.4.

Additional information about the issue

No response

Activity

  1. changed the title [-][5.5 beta] The `moduleDetection` option is ignored[/-] [+][5.5 beta] The `moduleDetection` option is ignored for `verbatimModuleSyntax` error[/+] on May 26, 2024
  2. jakebailey commented on May 26, 2024

    @jakebailey
    Member

    That option doesn't control anything to do with ESM versus CJS, it's controlling "module" (uses some form of exports, declarations are local) versus "script" (all globals, like a script tag).

  3. robpalme commented on May 27, 2024

    @robpalme

    This sounds similar (but not the same) as the 5.5 issue we hit of *.ts ES modules being emitted as CommonJS despite all tsconfig options conveying that input and output should all be ESM, e.g. "module": "esnext".

    The root cause seems to be the intentional decision to respect package.json's "type": "commonjs" so that it takes precedence over tsconfig, i.e. input and output will be assumed to be CJS if the source file is *.ts and there's no way in tsconfig to stop this.

    In our case we have a build system that up to now intentionally ignored package.json so this coupling was unwelcome, but hey, maybe we just have an odd use-case. Nicolò Ribaudo (@nicolo-ribaudo) what is your use-case for wanting this decoupling of tsconfig and package.json semantics?

  4. nicolo-ribaudo commented on May 27, 2024

    @nicolo-ribaudo
    ContributorAuthor

    I am using TypeScript only for type checking, and I'm using Babel to do all transpilation. My build system will transpile those files either to ESM or to CJS and put them in appropriate folders with their own package.json file that has the correct package.json#type.

    These restriction seem to be only necessary when TypeScript is emitting JS files, and even in that case they should be based on the package.json relative to the output files and not to the input files.

    In the new TS5.5 behavior, how would I have to update my tsconfig to keep being able to have the following, when not emitting JS files through tsc?

    • ESM syntax in .ts files
    • export = in .cts files
    • package.json#type: commonjs in the root
    • package.json#type: module in the ESM dist folder

    What I find surprising about this new behavior is that my module option is not set to one of the possible node* values, so I would expect it to not be affected by the Node.js-specific package.json#type.


    EDIT: It seems I can just disable verbatimModuleSyntax: true, module: ESNext and @ts-ignore the errors about using require as a variable name, I need to check if this affects anything else.

    EDIT2: That doesn't work because then TS errors on import handleMessage = ... in .cts files

  5. nicolo-ribaudo commented on May 27, 2024

    @nicolo-ribaudo
    ContributorAuthor

    I guess what I would like to have is an option to tell TS "I know what I'm doing about modules syntax, please don't error when you think you won't be able to emit it correctly", or an option to restore the previous behavior.

  6. fatcerberus commented on May 27, 2024

    @fatcerberus

    and even in that case they should be based on the package.json relative to the output files and not to the input files.

    IIRC this was actually tried. I don’t remember the exact reasoning but it turned out to not really be viable. See discussion at #54593 and other issues linked therein.

  7. acutmore commented on May 28, 2024

    @acutmore
    Contributor

    This sounds similar (but not the same) as the 5.5 issue we hit of *.ts ES modules being emitted as CommonJS despite all tsconfig options conveying that input and output should all be ESM, e.g. "module": "esnext".

    Some more context here: #58587 (comment).
    Our tooling does not emit a Node.js package, the build output won't contain a package.json. So any inference made about the content of the .ts files based on the package.json can cause us issues. In the past this was mostly limited to npm auto-complete suggestions appearing which won't be available in this particular runtime. However with 5.5 this now extends to causing build errors which can only be addressed by modifying the package.json which just so happens to be in a parent directory of the project.

  8. andrewbranch commented on Jun 6, 2024

    @andrewbranch
    Member

    Why are folks using an explicit "type": "commonjs" over omitting "type"? Preemptive performance optimization for --experimental-detect-module?

  9. nicolo-ribaudo commented on Jun 7, 2024

    @nicolo-ribaudo
    ContributorAuthor

    Just because type: commonjs and no type should have the same meaning, and in this case I prefer to be explicit.

    Does TS handle those two cases differently?

  10. andrewbranch commented on Jun 7, 2024

    @andrewbranch
    Member

    It does now outside of node16/nodenext. "type": "commonjs" is a more explicit signal than no "type". If you’re not targeting Node.js, it might be reasonable to leave that field unset and have ESM files, since Bun and most bundlers have no issue with that. But if you set "type": "commonjs", we take that as a signal that you at least want compatibility with Node.js, so we will use that signal to resolve ambiguities and prevent you from emitting something that will totally break it.

    they should be based on the package.json relative to the output files and not to the input files

    See #54546

  11. changed the title [-][5.5 beta] The `moduleDetection` option is ignored for `verbatimModuleSyntax` error[/-] [+][5.5 beta] package.json `"type"` lookup in non-Node.js `module` is unexpected[/+] on Jun 10, 2024
  12. andrewbranch commented on Jun 11, 2024

    @andrewbranch
    Member

    Nicolò Ribaudo (@nicolo-ribaudo) Ashley Claymore (@acutmore) could you try the build at #58825 and see if that addresses your issues? I think it should, but getting some definite feedback on real projects would be great since we’re so close to the final 5.5 release here.

  13. andrewbranch commented on Jul 9, 2024

    @andrewbranch
    Member

    Closed by #58831 / #58857

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Needs InvestigationThis issue needs a team member to investigate its status.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions