最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why TypeScript dont see exports of package? (with module: CommonJS and moduleResolution: Node) - Stack Overflow

programmeradmin4浏览0评论

i have NPM package that build for ESM and CJS formats in dist folder of package root

  • dist/esm - modules with ESM
  • dist/cjs - modules with CJS
  • dist/types - typings for all of modules

also in package.json there is export field like:

{
  "exports": {
    "./foo": {
      "types": "./dist/types/foo.d.ts",
      "require": "./dist/cjs/foo.js",
      "import": "./dist/esm/foo.js",
      "default": "./dist/esm/foo.js"
    },
    "./bar": {
      "types": "./dist/types/bar/index.d.ts",
      "require": "./dist/cjs/bar/index.js",
      "import": "./dist/esm/bar/index.js",
      "default": "./dist/esm/bar/index.js"
    },
    "./hello/world": {
      "types": "./dist/types/hello/world/index.d.ts",
      "require": "./dist/cjs/hello/world/index.js",
      "import": "./dist/esm/hello/world/index.js",
      "default": "./dist/esm/hello/world/index.js"
    }
  }
}

as you can see foo is a alias for foo.js BUT bar is alias for bar/index.js

and wneh i use this package in other project with TypeScript, tsc dont see bar and hello/world

it see only foo

import foo from 'my-pkg/foo' // WORKS FINE 
import bar from 'my-pkg/bar'; // NOT WORKING (cannot find declarations for...)
import helloWorld from 'my-pkg/hello/world'; // NOT WORKING (cannot find declarations for...)

Why does it work like that?

In Node.js without TypeScript it works in ESM and CJS fine without errors.

Only TypeScript can not find type definitions

i have NPM package that build for ESM and CJS formats in dist folder of package root

  • dist/esm - modules with ESM
  • dist/cjs - modules with CJS
  • dist/types - typings for all of modules

also in package.json there is export field like:

{
  "exports": {
    "./foo": {
      "types": "./dist/types/foo.d.ts",
      "require": "./dist/cjs/foo.js",
      "import": "./dist/esm/foo.js",
      "default": "./dist/esm/foo.js"
    },
    "./bar": {
      "types": "./dist/types/bar/index.d.ts",
      "require": "./dist/cjs/bar/index.js",
      "import": "./dist/esm/bar/index.js",
      "default": "./dist/esm/bar/index.js"
    },
    "./hello/world": {
      "types": "./dist/types/hello/world/index.d.ts",
      "require": "./dist/cjs/hello/world/index.js",
      "import": "./dist/esm/hello/world/index.js",
      "default": "./dist/esm/hello/world/index.js"
    }
  }
}

as you can see foo is a alias for foo.js BUT bar is alias for bar/index.js

and wneh i use this package in other project with TypeScript, tsc dont see bar and hello/world

it see only foo

import foo from 'my-pkg/foo' // WORKS FINE 
import bar from 'my-pkg/bar'; // NOT WORKING (cannot find declarations for...)
import helloWorld from 'my-pkg/hello/world'; // NOT WORKING (cannot find declarations for...)

Why does it work like that?

In Node.js without TypeScript it works in ESM and CJS fine without errors.

Only TypeScript can not find type definitions

Share Improve this question asked Oct 12, 2023 at 11:26 krutookrutoo 4055 silver badges17 bronze badges 1
  • 1 In addition to what Jared wrote, see nodejs/api/packages.html#dual-monjses-module-packages – Bergi Commented Oct 13, 2023 at 18:19
Add a ment  | 

2 Answers 2

Reset to default 6

This may not answer your question but is important for what you're trying to acplish and is too long for a ment.

This isn't going to work the way you've implemented it, at least not at the time I'm writing this. This is unreasonably hard to do, so don't feel bad. And now I show you how deep the rabbit hole goes...

When you don't have an exports map node will respect your main and module entries in your package.json and will treat .js files the correct way even based on whether they were imported or required as long as you don't set the type to "module".

But once you add an exports map it takes precedence, and all .js files will be treated as either CJS or ESM depending on what you set type to in package.json, regardless of whether it's the import or require path in the exports map. So that gives you three options:

  1. Don't use an exports map, set type to "monjs" (or omit it) and use the module property to point to your ESM entry point.
  2. Change all your esm files to .mjs (and add .mjs to all your imports)
  3. Change all your cjs files to .cjs (and add .cjs to all your requires)

The problem with options #2 and #3 is that the Typescript piler will not add it for you, and they have repeatedly refused to implement this.

Worth noting that even though the spec says that the extension for ESM imports should be '.js' in practice pretty much every up-to-date tool (e.g. Typescript, Rollup, Webpack, Vite) and up-to-date engine (e.g. V8, Webkit) will accept '.mjs'.

You can hack your way through it with shell scripts to replace the file extension with find/mv and sed to append the file extension on your import statements, you can do it less hackily by using a real parser to achieve the same oute, or you can use something like this package that does it for you.

If you want to see all this in action here's an example I wrote on GitHub.

And here are some more resources, shout out to Bergi in the ments on the question:

https://nodejs/api/esm.html#modules-ecmascript-modules

https://nodejs/api/packages.html#dual-monjses-module-packages

Good luck!

In the importing workspace tsconfig.json file, set moduleResolution to "Bundler".

{
  "$schema": "https://json.schemastore/tsconfig",
  "pilerOptions": {
    "strict": true,
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "jsx": "preserve",
    "jsxImportSource": "solid-js",
    "types": ["vite/client"],
    "noEmit": true,
    "isolatedModules": true,
    "skipLibCheck": true,
    "noUncheckedIndexedAccess": true
  }
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论