Skip to content

tsc ignores errors in an .mjs module with the same name as an .mts moduleΒ #47796

Closed

Description

Bug Report

tsc incorrectly ignores type errors in an .mjs module if there is a sibling .mts module with the same name.

πŸ”Ž Search Terms

  • esm
  • mjs
  • mts
  • sibling
  • tsc
  • errors

πŸ•— Version & Regression Information

  • typescript@4.6.0-dev.20220207

⏯ Playground Link

How do you setup a multiple module project in the TypeScript online playground?

πŸ’» Code

package.json:

{
  "name": "tsc-missing-errors-demo",
  "private": true,
  "devDependencies": {
    "typescript": "^4.6.0-dev.20220207"
  },
  "scripts": {
    "types": "tsc -p jsconfig.json"
  }
}

jsconfig.json:

{
  "compilerOptions": {
    "module": "node12",
    "noEmit": true,
    "strict": true
  },
  "typeAcquisition": {
    "enable": false
  }
}

.vscode/settings.json

{
  "typescript.disableAutomaticTypeAcquisition": true,
  "typescript.enablePromptUseWorkspaceTsdk": true,
  "typescript.tsdk": "node_modules/typescript/lib"
}

a.mjs:

// @ts-check

/** @typedef {import("a").default} A */

a.mts:

import b from "b";

Run in Terminal (after npm install):

npm run types

πŸ™ Actual behavior

The VS Code editor correctly shows the TypeScript type errors in both a.mjs and a.mts:

Screen Shot 2022-02-08 at 12 46 17 pm

The tsc CLI only shows the a.mts error, and incorrectly ignores the error in a.mjs.

Screen Shot 2022-02-08 at 12 46 29 pm

It doesn't matter if the sibling .mts file with the same name has an error or not; just it's presence causes errors in the .mjs file to be hidden:

Screen Shot 2022-02-08 at 12 46 41 pm

πŸ™‚ Expected behavior

The tsc CLI should display all TypeScript type errors in project modules, regardless if any have the same name as a sibling with a different extension.

Activity

  1. MartinJohns commented on Feb 8, 2022

    @MartinJohns
    Contributor

    This is working as intended. The JavaScript file is considered a build artifact of the TypeScript file, it's just output.

  2. jaydenseric commented on Feb 8, 2022

    @jaydenseric
    Author

    This is working as intended. The JavaScript file is considered a build artifact of the TypeScript file, it's just output.

    But a.mjs is not a build artifact, and TypeScript shouldn't assume that it is. All of my type safe TypeScript v4.6-dev.x supporting packages have zero build step; I write by hand the exact .mjs and .mts modules I want to publish in package exports. Both types of modules contain types (via JSDoc comments for .mjs) that need to be type checked as I'm editing them via VS Code and in GitHub Actions CI via the tsc CLI.

    The project jsconfig.json has compilerOptions.noEmit configured to true and even if the project did have a build step, why would tsc assume the a.mjs file came from the sibling a.mts file? Builds can be configured to place the compiled files anywhere. Within .mjs and .mts modules ESM import paths must specify the file extensions, so the files being siblings has no special meaning as no tools should ever be trying to resolve one or the other from extensionless import paths.

    The sibling a.mjs and a.mts modules both being published package exports is not a particularly exotic approach; for example a.mjs could be for browser projects to deep import and a.mts for Deno projects to deep import. Both need to be type checked independently and could have quite different contents.

    Even if I am mistaken about any of the above, why would VS Code show type errors in a.mjs, if it's just a "build artifact" and should be ignored for type checking? VS Code has all the same config and information that the tsc CLI has yet they disagree on the errors, so surely there is a bug somewhere here.

  3. jaydenseric commented on Feb 8, 2022

    @jaydenseric
    Author

    Out of curiosity, I tried configuring compilerOptions.outDir to "dist" in jsconfig.json, so tsc should definitely know that a.mjs is not an artifact of the sibling a.mts yet still the bug persists; any type errors in a.mjs are ignored by the tsc CLI.

  4. jaydenseric commented on Feb 8, 2022

    @jaydenseric
    Author

    Ok, so compilerOptions.outDir (after removing compilerOptions.noEmit) doesn't apparently do anything within jsconfig.json, but it does with tsconfig.json.

    With this tsconfig.json:

    {
      "compilerOptions": {
        "allowJs": true,
        "checkJs": true,
        "module": "Node12",
        "strict": true,
        "outDir": "dist"
      },
      "typeAcquisition": {
        "enable": false
      }
    }

    And with the package types script updated to tsc -p tsconfig.json the dist folder is created, but with only a.mjs in it derived from the a.mts file. It still doesn't report any of the source a.mjs module type errors; it seems to totally skip it. What would be more intuitive is if both a.mjs and a.mts were processed like normal, but then whatever one is processed second overwrites the first compiled a.mjs in the compilerOptions.outDir. That way you get type check error feedback for both. Certainly if compilerOptions.noEmit is true then both should be type checked; the primary use case for that is to type check all the project modules.

    It would be great if TypeScript had a simple check-types command that totally avoids compiling modules and friction such as this.

    Side note; but node12 (lowercased) is a documented valid value for compilerOptions.module:

    Screen Shot 2022-02-08 at 6 12 55 pm

    Yet VS Code warns this is invalid, and suggests Node12 (uppercased):

    Screen Shot 2022-02-08 at 7 39 26 pm

    Only for tsconfig.json though; VS Code is happy with node12 within jsconfig.json:

    Screen Shot 2022-02-08 at 7 41 41 pm

  5. weswigham commented on Feb 8, 2022

    @weswigham
    Member

    Explicitly list your input files if you actually want to include both - the compiler only automatically pulls in one copy of a file with the same basename (the most TS-y one). (Do note, this will cause other issues like the compiler warning you that they share an emit path if you have emit one!)

  6. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions