Ser*_*tin 14 node.js typescript es6-modules
随着Typescript 4.7 中添加的ECMAScript 模块支持,在 TS 构建过程中可能会涉及几个新的文件扩展名.mjs
,包括.d.mts
. 如果项目启用了此功能,TS 编译器在进行模块解析(定位要导入的文件)时管理起来会更加复杂。新的 ESM 文件扩展名有两种简单的模块:
.js
实现、.d.ts
声明文件.mjs
实现、.d.mts
声明文件并非所有包都符合上述类别。有些软件包附带了.js
和.mjs
版本的实现,但只有.d.ts
声明文件,没有 .d.mts
本案的解决规则是什么?它似乎.mjs
被优先考虑.js
,但拒绝工作,.d.mts
如果您不拥有导入的模块,那么如果没有它,就会出现问题。不修改包就可以解决这个问题吗?
对于通过以下配置启用 ESM 的项目
// package.json
"type": "module"
// tsconfig.json
"module": "Node16",
"moduleResolution": "node16"
Run Code Online (Sandbox Code Playgroud)
这取决于一个软件包(例如js-base64),该软件包附带.js
, .mjs
,.d.ts
但没有.d.mts
$ ls -l node_modules/js-base64
base64.d.ts
base64.js
base64.mjs
Run Code Online (Sandbox Code Playgroud)
然后当我尝试导入它时
// myfile.ts
import { Base64 } from 'js-base64'
Run Code Online (Sandbox Code Playgroud)
我收到错误:
找不到模块“js-base64”的声明文件。'/myproj/node_modules/js-base64/base64.mjs' 隐式具有 'any' 类型
但是,如果我这样做
$ ln -s node_modules/js-base64/base64.d.ts node_modules/js-base64/base64.d.mts
Run Code Online (Sandbox Code Playgroud)
然后错误就消失了,这对我来说表明它.d.ts
被故意忽略了。
JΛY*_*ÐΞV 23
上面的问题询问一个package.json
文件,即 AToW (在撰写本文时)是这样配置的。
{\n "main": "base64.js",\n "module": "base64.mjs",\n "types": "base64.d.ts",\n\n "files": [\n "base64.js",\n "base64.mjs",\n "base64.d.ts"\n ],\n\n "exports": {\n ".": {\n "import": "./base64.mjs",\n "require": "./base64.js"\n },\n "./package.json": "./package.json"\n },\n}\n
Run Code Online (Sandbox Code Playgroud)\n 当问题的作者将包文件作为 ESM 模块导入时,他会使用 import 语句来尝试访问它,但是,他的“TypeScript 编译器”(又名 )每次TSC
都会抛出错误(如下所示)尝试使用导入的模块。
Could not find a declaration file for module: "js-base64" \'/myproj/node_modules/js-base64/base64.mjs\' implicitly has an \'any\' type
模块可以在不重新配置包的情况下解析吗?为什么创建符号链接(如谢尔盖的问题所示)似乎可以修复正在发生的错误?
\n这是一个双模块 Node 包,这意味着它包含两个版本:一个 CJS 版本和一个 ESM 版本。它被配置为仅在模块的入口点使用不同的文件,包的其余部分(理论上)应该是相同的。
\n为两个不同入口点配置的文件可以在package.json
我在此答案最顶部发布的代码片段中看到。
在我们深入讨论之前,我想澄清一下,package.json
文件配置有一个问题,但是,在大多数情况下,它的配置是正确的。&入口点 & 构建都运行良好,唯一的问题是,当 TypeScript 用户将模块导入为ECMAS-Module \xe2\x80\x94又名ESM
\ xe2\x80\x94 时,它不会解析类型,因此,当问题作者尝试导入和使用包时,TypeScript 编译器会抛出类型错误。CJS
ESM
不将 with 解析为类型化模块会产生一些明显的影响。虽然它们对大多数人来说都是显而易见的,但最好将它们涵盖在内,以确保所有读者在讨论中都站在同一点上。
\n如果您使用纯 JavaScript,您可能不会注意到任何问题。JS 不使用类型,因此,将包导入到纯 JavaScript 代码库中,应该能够作为“ES-Module”或“Common-JS Module”来完成 \xe2\x80\x94 ” \xe2\x80\x94 没有遇到任何问题。
\nimport { ... } from \'js-base64\'
使用 TypeScript 的人应该能够通过&/或 a来解析模块require(\'js-base64\')
语句解析模块,并且所有内容都应该解析为键入的内容。
尝试在 ESM 环境中使用 TypeScript \xe2\x80\x94 导入包的人将收到类型错误,并且他们应该注意到该包未使用类型进行解析。
\nbase64.d.ts
文件中吗?因此,包是用 TypeScript 编写的,通常双模块包将用 TypeScript 编写,或者至少使用某些转译器进行转译。在这种情况下,该包无疑是 TS 创作的包。我没有彻底检查它的代码,但如果它曾经是纯 JS,并且在某个时候转换为 TS,我不会感到惊讶。不管怎样,它确实发出了正确的 TSC.d.ts
声明文件。
由于配置方式的原因,它无法解决。默认情况下,该包配置为解析为“Common-JS Module”。基础package.json
文件不包含“类型”字段,因此它默认为CJS模块。文件package.json
的"type"
字段可以设置为...
"commonjs"
(又名 CJS) \xc2\xa0 或,"module"
(又名 ESM)"type"
字段会导致包解析为CJS模块。为 ESM 配置模块,尤其是在尝试同时支持 CJS 时,已成为一项非常复杂的考验,并且目前在涉及 TypeScript 编写的包时,许多人并不理解它。这是因为,尽管 ESM 标准早在 2015 年就已包含在 ECMA-262 规范中,但对 ESM 的大部分支持都是新的。
\n需要注意的重要一点是,包维护者使用 package.json 文件的“exports”字段来为两种模块类型定义单独的入口点。
\n "types": "base64.d.ts",\n "exports": {\n ".": {\n "import": "./base64.mjs", // ESM entry point\n "require": "./base64.js" // CJS entry point\n },\n "./package.json": "./package.json"\n },\n
Run Code Online (Sandbox Code Playgroud)\n他本可以反过来做,但他没有,他按照你在上面看到的方式做了。
\n问题可以在上面的代码片段中看到,类型字段是他告诉 TSC 当包作为模块导入时声明文件在哪里的地方,问题是,正如我上面指出的,包默认解析为CJS 模块,尽管定义了 ESM 入口点。
\n为了解决这个问题,包需要有一个声明文件,该文件的名称和文件扩展名与设置为 ESM 入口点的文件具有相同的名称和文件扩展名。解决问题的另一种方法是,base64.d.ts
需要显式配置已存在的声明文件,以将文件集设置为 ESM 入口点(即base64.mjs
)进行解析。
package.json
集"exports"
字段中的配置集。// jD3V\'s adjusted package configuration\n\n{\n "main": "base64.js",\n "module": "base64.mjs",\n "types": "base64.d.ts",\n\n "files": [\n "base64.js",\n "base64.mjs",\n "base64.d.ts"\n ],\n\n "exports": {\n ".": {\n "import": "./base64.mjs",\n "require": "./base64.js",\n "types": "./base64.d.ts"\n },\n },\n}\n
Run Code Online (Sandbox Code Playgroud)\n在上面您可以看到该包的配置使得TypeScript现在可以推断(从包含在“exports”字段中的“types”字段)base64.d.ts 文件应该通过所有导出来解析。
\nexports
这样写该字段: "exports": {\n ".": {\n // Entry-point for `import "my-package"` in ESM\n "import": {\n\n\n // Where TypeScript will look.\n "types": "./base64.d.ts",\n\n\n // Where Node.js will look.\n "default": "./base64.mjs"\n },\n\n "require": "./base64.js",\n },\n }\n
Run Code Online (Sandbox Code Playgroud)\npackage.json
JD3V文件和 TS v4.7 代码片段之间的区别在于,"import"
字段(在"exports"
字段中)将对象作为其分配的值,因此;当types
在“TS v4.7”中设置位置时,它会为“base64.mjs”设置一个特定文件,就像在 JD3V 片段中一样,它会为所有导出设置一个特定的“类型”位置。
package.json
导出、导入和自引用 归档时间: |
|
查看次数: |
18731 次 |
最近记录: |