Skip to content

Module resolution: ESM-style namespace importing is broken #58817

New issue

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

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
kungfooman opened this issue Jun 10, 2024 · 5 comments
Closed

Module resolution: ESM-style namespace importing is broken #58817

kungfooman opened this issue Jun 10, 2024 · 5 comments
Labels
Duplicate An existing issue was already created

Comments

@kungfooman
Copy link

kungfooman commented Jun 10, 2024

Demo Repo

https://github.com/kungfooman/ts_esm_fail

Which of the following problems are you reporting?

Something else more complicated which I'll explain in more detail

Demonstrate the defect described above with a code sample.

import * as ts from 'typescript';
// What could possibly go wrong... besides everything.
console.log("ts.ScriptTarget.Latest", ts.ScriptTarget.Latest);

Run tsc --showConfig and paste its output here

> error TS5081: Cannot find a tsconfig.json file at the current directory: /var/www/html/ts_esm_fail.

I have a jsconfig.json, fix your tool. But tsc -p jsconfig.json prints nothing (no errors).

Run tsc --traceResolution and paste its output here

Version 4.9.3
tsc: The TypeScript Compiler - Version 4.9.3                                                                            
                                                                                                                     TS 
COMMON COMMANDS

  tsc
  Compiles the current project (tsconfig.json in the working directory.)

  tsc app.ts util.ts
  Ignoring tsconfig.json, compiles the specified files with default compiler options.

  tsc -b
  Build a composite project in the working directory.

  tsc --init
  Creates a tsconfig.json with the recommended settings in the working directory.

  tsc -p ./path/to/tsconfig.json
  Compiles the TypeScript project located at the specified path.

  tsc --help --all
  An expanded version of this information, showing all possible compiler options

  tsc --noEmit
  tsc --target esnext
  Compiles the current project, with additional settings.

COMMAND LINE FLAGS

     --help, -h  Print this message.

    --watch, -w  Watch input files.

          --all  Show all compiler options.

  --version, -v  Print the compiler's version.

         --init  Initializes a TypeScript project and creates a tsconfig.json file.

  --project, -p  Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.

    --build, -b  Build one or more projects and their dependencies, if out of date

   --showConfig  Print the final configuration instead of building.

COMMON COMPILER OPTIONS

               --pretty  Enable color and formatting in TypeScript's output to make compiler errors easier to read.
                  type:  boolean
               default:  true

           --target, -t  Set the JavaScript language version for emitted JavaScript and include compatible library declarations.
                one of:  es3, es5, es6/es2015, es2016, es2017, es2018, es2019, es2020, es2021, es2022, esnext
               default:  es3

           --module, -m  Specify what module code is generated.
                one of:  none, commonjs, amd, umd, system, es6/es2015, es2020, es2022, esnext, node16, nodenext
               default:  undefined

                  --lib  Specify a set of bundled library declaration files that describe the target runtime environment.
           one or more:  es5, es6/es2015, es7/es2016, es2017, es2018, es2019, es2020, es2021, es2022, esnext, dom, dom.iterable, webworker, webworker.importscripts, webworker.iterabl                         e, scripthost, es2015.core, es2015.collection, es2015.generator, es2015.iterable, es2015.promise, es2015.proxy, es2015.reflect, es2015.symbol, es2015.symbol.                         wellknown, es2016.array.include, es2017.object, es2017.sharedmemory, es2017.string, es2017.intl, es2017.typedarrays, es2018.asyncgenerator, es2018.asyncitera                         ble/esnext.asynciterable, es2018.intl, es2018.promise, es2018.regexp, es2019.array, es2019.object, es2019.string, es2019.symbol/esnext.symbol, es2019.intl, e                         s2020.bigint/esnext.bigint, es2020.date, es2020.promise, es2020.sharedmemory, es2020.string, es2020.symbol.wellknown, es2020.intl, es2020.number, es2021.prom                         ise/esnext.promise, es2021.string, es2021.weakref/esnext.weakref, es2021.intl, es2022.array/esnext.array, es2022.error, es2022.intl, es2022.object, es2022.sh                         aredmemory, es2022.string/esnext.string, esnext.intl
               default:  undefined

              --allowJs  Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files.
                  type:  boolean
               default:  false

              --checkJs  Enable error reporting in type-checked JavaScript files.
                  type:  boolean
               default:  false

                  --jsx  Specify what JSX code is generated.
                one of:  preserve, react, react-native, react-jsx, react-jsxdev
               default:  undefined

      --declaration, -d  Generate .d.ts files from TypeScript and JavaScript files in your project.
                  type:  boolean
               default:  `false`, unless `composite` is set

       --declarationMap  Create sourcemaps for d.ts files.
                  type:  boolean
               default:  false

  --emitDeclarationOnly  Only output d.ts files and not JavaScript files.
                  type:  boolean
               default:  false

            --sourceMap  Create source map files for emitted JavaScript files.
                  type:  boolean
               default:  false

              --outFile  Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output.

               --outDir  Specify an output folder for all emitted files.

       --removeComments  Disable emitting comments.
                  type:  boolean
               default:  false

               --noEmit  Disable emitting files from a compilation.
                  type:  boolean
               default:  false

               --strict  Enable all strict type-checking options.
                  type:  boolean
               default:  false

                --types  Specify type package names to be included without being referenced in a source file.

      --esModuleInterop  Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility.
                  type:  boolean
               default:  false

You can learn about all of the compiler options at https://aka.ms/tsc

Paste the package.json of the importing module, if it exists

{
  "name": "ts_esm_fail",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "node src/index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "typescript": "^5.4.5"
  }
}

Paste the package.json of the target module, if it exists

{
    "name": "typescript",
    "author": "Microsoft Corp.",
    "homepage": "https://www.typescriptlang.org/",
    "version": "5.4.5",
    "license": "Apache-2.0",
    "description": "TypeScript is a language for application scale JavaScript development",
    "keywords": [
        "TypeScript",
        "Microsoft",
        "compiler",
        "language",
        "javascript"
    ],
    "bugs": {
        "url": "https://github.com/Microsoft/TypeScript/issues"
    },
    "repository": {
        "type": "git",
        "url": "https://github.com/Microsoft/TypeScript.git"
    },
    "main": "./lib/typescript.js",
    "typings": "./lib/typescript.d.ts",
    "bin": {
        "tsc": "./bin/tsc",
        "tsserver": "./bin/tsserver"
    },
    "engines": {
        "node": ">=14.17"
    },
    "files": [
        "bin",
        "lib",
        "!lib/enu",
        "LICENSE.txt",
        "README.md",
        "SECURITY.md",
        "ThirdPartyNoticeText.txt",
        "!**/.gitattributes"
    ],
    "devDependencies": {
        "@esfx/canceltoken": "^1.0.0",
        "@octokit/rest": "^20.0.2",
        "@types/chai": "^4.3.11",
        "@types/glob": "^8.1.0",
        "@types/microsoft__typescript-etw": "^0.1.3",
        "@types/minimist": "^1.2.5",
        "@types/mocha": "^10.0.6",
        "@types/ms": "^0.7.34",
        "@types/node": "latest",
        "@types/source-map-support": "^0.5.10",
        "@types/which": "^3.0.3",
        "@typescript-eslint/eslint-plugin": "^6.19.0",
        "@typescript-eslint/parser": "^6.19.0",
        "@typescript-eslint/utils": "^6.19.0",
        "azure-devops-node-api": "^12.3.0",
        "c8": "^9.1.0",
        "chai": "^4.4.1",
        "chalk": "^4.1.2",
        "chokidar": "^3.5.3",
        "diff": "^5.1.0",
        "dprint": "^0.45.0",
        "esbuild": "^0.20.0",
        "eslint": "^8.56.0",
        "eslint-formatter-autolinkable-stylish": "^1.3.0",
        "eslint-plugin-local": "^3.1.0",
        "eslint-plugin-no-null": "^1.0.2",
        "eslint-plugin-simple-import-sort": "^10.0.0",
        "fast-xml-parser": "^4.3.3",
        "glob": "^10.3.10",
        "hereby": "^1.8.9",
        "jsonc-parser": "^3.2.0",
        "minimist": "^1.2.8",
        "mocha": "^10.2.0",
        "mocha-fivemat-progress-reporter": "^0.1.0",
        "ms": "^2.1.3",
        "node-fetch": "^3.3.2",
        "playwright": "^1.41.0",
        "source-map-support": "^0.5.21",
        "tslib": "^2.6.2",
        "typescript": "5.4.0-dev.20240119",
        "which": "^3.0.1"
    },
    "overrides": {
        "typescript@*": "$typescript"
    },
    "scripts": {
        "test": "hereby runtests-parallel --light=false",
        "test:eslint-rules": "hereby run-eslint-rules-tests",
        "build": "npm run build:compiler && npm run build:tests",
        "build:compiler": "hereby local",
        "build:tests": "hereby tests",
        "build:tests:notypecheck": "hereby tests --no-typecheck",
        "clean": "hereby clean",
        "gulp": "hereby",
        "lint": "hereby lint",
        "format": "dprint fmt",
        "setup-hooks": "node scripts/link-hooks.mjs"
    },
    "browser": {
        "fs": false,
        "os": false,
        "path": false,
        "crypto": false,
        "buffer": false,
        "@microsoft/typescript-etw": false,
        "source-map-support": false,
        "inspector": false,
        "perf_hooks": false
    },
    "packageManager": "npm@8.19.4",
    "volta": {
        "node": "20.1.0",
        "npm": "8.19.4"
    }
}

Any other comments can go here

I'm doing the most normal ESM-style namespace importing, which everyone would simply expect to work, even your own types think so:

image

However, for some reason TS still believes that it only has to ship non-ESM files. It's 2024, why?!

@kungfooman
Copy link
Author

Some weeks ago I couldn't be bothered anymore waiting for ESM in TS, so I fixed the build script myself: kungfooman@eec5f8d

It's rather simple and works for my use cases, but YMMV.

@fatcerberus
Copy link

I have a jsconfig.json, fix your tool.

tsc -p jsconfig.json

@kungfooman
Copy link
Author

@fatcerberus Thank you, edited, the project has seemingly zero errors (no output), which is the error here. 😅

@jakebailey
Copy link
Member

jakebailey commented Jun 10, 2024

Copying the text from your repo (please put this in the issue next time):

(base) homepc@home-pc:/var/www/html/ts_esm_fail$ npm run start

> ts_esm_fail@1.0.0 start
> node src/index.js

file:///var/www/html/ts_esm_fail/src/index.js:3
console.log("ts.ScriptTarget.Latest", ts.ScriptTarget.Latest);
                                                      ^

TypeError: Cannot read properties of undefined (reading 'Latest')
    at file:///var/www/html/ts_esm_fail/src/index.js:3:55
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:530:24)
    at async loadESM (node:internal/process/esm_loader:91:5)
    at async handleMainPromise (node:internal/modules/run_main:65:12)

Node.js v18.12.1
(base) homepc@home-pc:/var/www/html/ts_esm_fail$ 

This is a duplicate of #56366, fixed by #57133 for TS 5.5. Please try the RC or nightly, or write import ts from "typescript".

However, for some reason TS still believes that it only has to ship non-ESM files. It's 2024, why?!

Many, many, many reasons. See also #58419.

@jakebailey jakebailey added the Duplicate An existing issue was already created label Jun 10, 2024
@kungfooman
Copy link
Author

Hey @jakebailey, thank you for the information and all the work you put into ESM (I wasn't aware of it at all, I apologize)!

Please try the RC or nightly, or write import ts from "typescript".

So I could just fix it by npm i typescript@beta found on https://devblogs.microsoft.com/typescript/announcing-typescript-5-5-beta/

Thank you again, very happy that this is fixed soon and that ESM is actively worked on. 🚀

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants