Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
3 participants