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

Support recognizing TypeScript files imported with .js suffix #214

Closed
mon-jai opened this issue Feb 18, 2022 · 7 comments · Fixed by #255
Closed

Support recognizing TypeScript files imported with .js suffix #214

mon-jai opened this issue Feb 18, 2022 · 7 comments · Fixed by #255

Comments

@mon-jai
Copy link

mon-jai commented Feb 18, 2022

In TypeScript, it is valid to import TypeScript files with .js extension. TypeScript will match the coresponding .ts files if they exist. This behaviour is commonly used in Node.js projects as .js file extensions are required in Node.js ESM imports.

It would be great if ts-unused-exports also recognize variable imported with .js suffix.

Related: evanw/esbuild#1343 (comment), microsoft/TypeScript#16577 (comment), microsoft/TypeScript#16577 (comment)

Example

In this example project derived from example/simple, inc() from math.ts was imported with .js extension.

import inc from './math.js';

And TypeScript recognize it sucessfully.

56-18-22-235633

However, ts-unused-exports failed to recognize that the default import ofmath.ts was imported in app.ts.

Screenshot 2022-02-19 000527

@mrseanryan
Copy link
Collaborator

hm I'm not sure we will support imports of .js files in this way.

That link seems to be discussing ECMAScript (the spec for JavaScript).

However ts-unused-exports currently processes TypeScript.

Besides that, I don't really understand why this feature would be needed - isn't it possible use all TypeScript with Node.js ?

Perhaps if you can explain the use case a bit more, that would help ...

@mon-jai
Copy link
Author

mon-jai commented Feb 19, 2022

.js file extensions are required by Node.js ESM imports, and TypeScript won't add them for you by design.

Therefore, for any project that output target is ES6 or above, all import statements must be ended with .js extension (in TypeScript source files), so the compiled output will contain file extensions in import statements, and work on Node.js.

In fact, example/simple only works when the output format is set to commonjs. If I modify it to output ESM instead,

"target": "es6",
"module": "es6",

the compiled output won't run.

$ tsc && node app.js
node:internal/process/esm_loader:94
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'D:\GitHub\ts-unused-exports\example\simple\math' imported from D:\GitHub\ts-unused-exports\example\simple\app.js
Did you mean to import ../math.js?
    at new NodeError (node:internal/errors:371:5)
    at finalizeResolution (node:internal/modules/esm/resolve:394:11)
    at moduleResolve (node:internal/modules/esm/resolve:944:10)
    at defaultResolve (node:internal/modules/esm/resolve:1041:11)
    at ESMLoader.resolve (node:internal/modules/esm/loader:530:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:251:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:79:40)
    at link (node:internal/modules/esm/module_job:78:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v17.4.0

So if I am developing a project which must output ESM code, ts-unused-exports won't work for it.

Edit: explain the issue more clearly.

@ephys
Copy link

ephys commented Jul 1, 2022

Specifying the .js extension is the only way to load TypeScript files when using Node with native ES Modules, as ESM requires the extension to be specified and as @mon-jai said, TypeScript decided to not modify import paths at all (not replacing .ts with .js and not adding .js if the extension is unspecified)

@bbeesley
Copy link

Currently having to disable this tool in all our repos since migrating to node16/esm. There are plenty of details in the ts docs if you need to understand why we have to import like this now @mrseanryan .

@mrseanryan
Copy link
Collaborator

Hello - this is somewhat tricky to add support for...

Here is a PR that adds initial support:

#255

If someone can try it out, that would be great ...

@mrseanryan mrseanryan self-assigned this Dec 11, 2022
@mrseanryan
Copy link
Collaborator

Released as 9.0.0 - thank you

@mrseanryan mrseanryan unpinned this issue Dec 26, 2022
@ThomasAribart
Copy link

@mrseanryan Hello and thanks again for this wonderful library 🙌

It seems the issue has not been resolved when .js files are used in conjunction with tsconfig aliases. Here's the configuration on DynamoDB-Toolbox:

// tsconfig.json
{
  ...
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "baseUrl": "src",
    "target": "es2019",
    "rootDir": "src",
    "outDir": "dist/types",
    "declaration": true,
    ...
    "paths": {
      "~/*": ["*"]
    }
  }
}

When I run ts-unused-exports I get a lot of false positives. I have tried:

  • Removing a .js extension on a file with an absolute import (from '~/someFolder/someFile'): It worked as intended
  • Using a .js extension on a file with a relative import (from './someFile.js'): It also worked as intended

But the conjunction of the two (from '~/someFolder/someFile.js') did not.

Do you confirm that's the current behavior? Is it the desired one? Can I do something to help?

Many thanks, Thomas

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

Successfully merging a pull request may close this issue.

5 participants