Skip to content

generated output don't follow moduleSuffixes option #49586

Closed

Description

@ryanroe

Bug Report

typescript generated output don't follow moduleSuffixes option,

🔎 Search Terms

searched terms: moduleSuffixes, result none

🕗 Version & Regression Information

typescript@4.7.3 and typescript@next(4.8.0-dev.20220616)

💻 Code

create 2 ts files
a.web.ts

export const a = "web"

a.node.ts

export const a = "node"

create index.ts

import {a} from './a'

create tsconfig.json with

{
"moduleSuffixes":[".node",""]
}

run tsc -w

stackblitz link

🙁 Actual behavior

generated index.js directly imports a from './a'

🙂 Expected behavior

generated index.js directly imports a from './a.node' according to moduleSuffixes

Activity

  1. Josh-Cena commented on Jun 17, 2022

    @Josh-Cena
    Contributor

    Nothing in TS re-writes import paths. They only inform TS about existing path mappings.

  2. MartinJohns commented on Jun 17, 2022

    @MartinJohns
    Contributor

    according to moduleSuffixes

    What makes you think that's the purpose of moduleSuffixes? I couldn't find any documentation regarding this flag. Related: microsoft/TypeScript-Website#2423

  3. ryanroe commented on Jun 17, 2022

    @ryanroe
    Author

    according to moduleSuffixes

    What makes you think that's the purpose of moduleSuffixes? I couldn't find any documentation regarding this flag. Related: microsoft/TypeScript-Website#2423

    i read that from blog here , so i naively think that that's the purpose

  4. DanielRosenwasser commented on Jun 17, 2022

    @DanielRosenwasser
    Member

    Sorry it wasn't more explicit - we won't do path rewriting. moduleSuffixes is meant to inform TypeScript of how your runtime/resolver will resolve the paths.

    So if you have a bundler or resolver plugin that will try to look up .node-suffixed name, moduleSuffixes will allow TypeScript to understand that - but TypeScript will defer to that bundler/resolver to do that later and not touch the paths. React Native's Metro is the most well-known example of a bundler with a resolution strategy like this.

  5. typescript-bot commented on Jun 20, 2022

    @typescript-bot
    Contributor

    This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  6. cccRaim commented on Jul 28, 2022

    @cccRaim

    Daniel Rosenwasser (@DanielRosenwasser)
    I got the same issue, it's working as intended or not, maybe should ask Adam Foxman (@afoxman) .
    #48189

    // react-native use-case: import './foo' -> search for foo.ios.ts, then foo.native.ts, and finally foo.ts
    {
        "compilerOptions": {
            // empty string --> match without an extension
            "moduleSuffixes": [".ios", ".native", ""]
        }
    }

    The original intend is above.
    So if moduleSuffixes is [".node",""], ts should use *.node.ts first instead use *.ts, unless there is no *.node.ts file.
    But now ts use *.ts first, I think it's not work as intended.

  7. DanielRosenwasser commented on Jul 28, 2022

    @DanielRosenwasser
    Member

    It will resolve that way, but we won't rewrite the paths when we output JavaScript code. We expect that a loader of some sort will prefer foo.node.js over foo.js.

    If something isn't working for you, I'd guess it's probably because Node.js doesn't do that by default. You'll need to find some sort of loader hook for it.

  8. afoxman commented on Jul 28, 2022

    @afoxman
    Contributor

    Sorry this isn't clear. moduleSuffixes does appear to be working correctly. As Daniel Rosenwasser (@DanielRosenwasser) said, the intent is to teach TypeScript how modules are resolved by apps like Webpack/Metro. Not to change emitted code.

    This lets TypeScript build a matching file graph and run type-checking on it. For example, when building a React Native Android app, Metro will only bundle .android.ts files, it won't bundle .ios.ts files. So .ios.ts files should not be considered when type-checking Android builds.

  9. cccRaim commented on Jul 29, 2022

    @cccRaim

    Adam Foxman (@afoxman) Daniel Rosenwasser (@DanielRosenwasser)
    😂My fault, I misunderstood what the issue publisher meant.
    Rewrite is wrong.

    But I do have the wrong logic of module load though. Maybe I should publish a new issue.
    Thx reply.

  10. KlasikNormalBoy commented on Sep 5, 2022

    @KlasikNormalBoy

    I feel that documentation on https://www.typescriptlang.org/tsconfig#compilerOptions is very poor for paths and suffixes if this is the behaviour. It should clearly state that this will not change the output of TSC

  11. KlasikNormalBoy commented on Sep 5, 2022

    @KlasikNormalBoy

    I found that here: https://www.typescriptlang.org/docs/handbook/module-resolution.html#additional-module-resolution-flags.
    But this should be much more prominent on the tsconfig page, since this is the first entry point in looking for these options.

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