多年来,我一直在与这个问题作斗争。我似乎不知道如何可靠地使用TypeScript中的JavaScript库。
我似乎是意外地让它工作起来的,然后继续前进,多年来都没有重新访问这样的代码,直到外在的变化迫使它崩溃,就像今天我更新VS 2019时一样。
我花了好几天时间阅读有关模块、需求和加载程序的内容,但我越来越困惑。
示例。我想在我正在编写的TypeScript.ts
文件中使用DayJS。
这是示例代码。
import * as dayjs from 'dayjs'
dayjs().format()
我不能理解的是,由于两个原因,这种语法从未在任何库中适用于我:
- 它省略了指向
dayjs
文件夹的路径,对我来说应该是lib/dayjs
- 它没有指定文件,我以前对
moment.js
的工作引用指向moment.js
文件
不清楚'dayjs'
是文件夹还是文件。
复合学习的两个问题是:
- TypeScript无论找到了什么但找不到要加载的东西,还是路径无效/不存在,都会给出相同的错误
错误TS2307:找不到模块"lib/dayjs"或其相应的类型声明。
TypeScript似乎允许导入指向没有文件扩展名的文件,例如,此代码似乎满足并消除了上述错误,因为磁盘上有一个
index.js
文件。这个";灵活性";导致歧义和混乱。import * as dayjs from "lib/dayjs/index";
TypeScript文档本身没有给出从JavaScript库导入的示例,只是从其他.ts
文件导入,而没有扩展名。
以下是磁盘上的DayJS文件。
libdayjsesm
libdayjslocale
libdayjsplugin
libdayjsCHANGELOG.md
libdayjsdayjs.min.js
libdayjsindex.d.ts
libdayjslocale.json
libdayjspackage.json
libdayjsREADME.md
以下语法没有错误,TypeScript对其进行编译,甚至加载intellisense/文档。
import * as dayjs from "lib/dayjs/index.d.js";
但是那个文件不存在!所以我的网络应用程序无法运行,因为Chrome无法获取它。但是下面的无法编译,即使文件存在!!
import * as dayjs from "lib/dayjs/index.d.ts";
错误TS2691:导入路径不能以扩展名'.d.ts'结尾。请考虑导入"lib/dayjs/index"。
然而,当我按照错误的建议操作时,这也是Chrome的404
。
有人知道地球上发生了什么吗??
在TypeScript中使用JavaScript库的最终方法是什么?
更新
我现在已经使用了tsconfig.json
中的baseUrl
和paths
设置来获得在TypeScript中编译的导入语句,该语句在部署/托管时可转换到200 OK
的路径。
"compilerOptions": {
"target": "es5",
"module": "es2015",
"baseUrl": "./wwwroot/",
"paths": {
"lib/dayjs/dayjs.min.js": [ "lib/dayjs/index" ]
},
...
TypeScript intellisense告诉我,我对DayJS的使用是正确的。
var f = dayjs().format("dddd D MMMM YYYY");
var t = dayjs(date).format("dddd D MMMM YYYY");
但在浏览器中,Chrome报告了一个错误:
TimeHelpers.js:16 Uncaught TypeError:dayjs不是函数
我不知道。我可能会再试一次,但这给了我一些其他奇怪的错误,global
在其源代码的顶部是未定义的。
否则,显然我可以将dayjs声明为Any
以满足TS编译器的要求,然后使用老式的<script>
标记将其加载到页面上。这太疯狂了。
更新
我已经取得了足够的进展,在tsconfig.json
中添加了以下两行,并更改为
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
和
import dayjs from "lib/dayjs/dayjs.min.js"
我现在得到了一个其他人得到的错误,这让我松了一口气,因为至少我现在知道不要使用DayJS。
https://github.com/iamkun/dayjs/issues/313
更新
今天是漫长的一天,但取得了一些进展。
- 我根据我从文档中重读和重新解释的内容,在
tsconfig.json
中重新配置了baseUrl
和paths
- 我已经改为尝试
luxon
,但有问题 - VS代码和编译器看到了Luxon打字员和intellisense的工作
- 我在
gulpfile.js
中添加了一个小调整,改变了导入路径,这样Chrome就可以在部署时加载它 - 明天我会回去尝试一下,看看我是否能运用我的新知识,让其中一个包发挥作用
我会在一切就绪后发布一个完整的解释。
我有很多相同的挫折!很难让TypeScript与JavaScript很好地配合使用,而Microsoft文档又太迟钝了!
在您的情况下:指向库的路径总是在node_modules
中查找,因此在这种情况下,您不需要添加完整路径。
您也永远不需要import
一个.d.ts
文件。您只需将.d.ts
文件放在工作文件夹中的某个位置,VS Code就会检测到它
如果您有moment.js
的.d.ts
文件,您将在VS代码中获得类型完成。当您使用<script>
文件加载它时,不需要import moment.js
。
关于导入扩展:这取决于您是使用本机ES6模块还是使用模块绑定器。在后一种情况下,您不需要添加文件扩展名,因为模块bundler会为您解决这个问题。
以下是我学到的东西。买家要小心:这可能是不正确的。
对模块的本机支持对于JavaScript来说相对较新。多年来,为了分解大型代码库,库提供了对模块化代码的支持。
JavaScript通常作为一种应用程序语言在浏览器外使用,比如Node.js;浏览器中的客户端代码、服务器端和桌面独立应用程序代码。
存在各种各样的约定和语法来解决这个问题,如CommonJS(又名ServerJS)、AMD、UMD和ESM/ES6模块。
我不完全确定这一点,但我认为对于浏览器内的使用,您需要做额外的工作来使用模块。
-
添加一个额外的编译/编译/绑定工具,将所有模块代码文件拉到一个可部署的代码文件中。
-
添加一个模块加载器库,可以下载依赖的模块JS文件。
-
对于ESM,请确保用户的浏览器是最新的,然后确保导入语句指向JS文件的有效URL,包括其扩展名。
Node.js运行时可能有自己的语法和模块加载程序,我不知道。
TypeScript只是一个JavaScript编译器/传输程序,它是为Node.js和浏览器应用程序设计的。它的输出只是故事的一部分,通常需要进一步的操作或处理。与传统的代码编译器不同,仅仅因为编译器是愉快的并且没有错误,并不意味着TS生成的JS会自动运行。
例如,在我的案例中,我需要在Gulpfile.js
中执行查找-替换步骤,将一些import thing from "name"
模块名称更改为工作URL。
TypeScript需要一个打字员文件来帮助它的编译器。此文件仅在编辑期间有用,用于智能感知和检查您对库的使用是否完美。一旦运输,就不会使用。现在,许多包都附带了打字员文件、.d.ts
文件,TS通常只是神奇地找到它们。
NPM包通常不是为ES6构建的。包中的JS文件本身可能是经过转换的源代码的产物。文档可能会显示使用ESM的语法,但可能不会说明要使用包中的哪个JS文件,甚至可能包括一个或多个兼容文件。
您甚至可能需要在一个包中进一步编译、传输或捆绑JS文件。这通常是环境知识,没有明确说明。
在Luxon的情况下,该包不包含ESM兼容代码,但包含CommonJS和<script>
标签的代码。ESM兼容代码是手动下载的。
在moment.js
的情况下,如果文档说明要导入哪个moment.js
文件,那么问题早就解决了。
我自己找到的最接近的是moment/src/moment.js
,它看起来像ES6代码,有一个默认导出,但在浏览器中失败了,因为同一个文件从JS文件导入,而没有指定.js
扩展名,这是web浏览器不支持的。
最后,在SO上的某个人的帮助下,我在dist
文件夹中发现了一个看起来像是一个大的、单个的、捆绑的moment.js
,带有默认导出。我有没有提到JS包的作者使用了晦涩难懂的名字?
不幸的是,我一直在尝试许多不同的约会时间包,并对TypeScript设置进行了大量的修改,所以我没有早点发现这个问题——我可能直到最后8个小时才知道该找什么。
-
在您的NPM包中,找到大的";预捆扎";(?)带有ES6外观代码的JS文件,通常可以通过在文件中搜索
export default
来识别,通常在底部。 -
使用以下
tsconfig.json
"目标":"es6";,"模块":"es2015";,"esModuleInterop":是的,"allowSyntheticDefaultImports":是的,//根据需要设置baseUrl和路径
-
使用以下语法消费,例如
moment.js
从"moment/minum"导入moment//根据需要更改模块名称/路径
-
TSC运行后,使用查找-替换任务将TS发出的模块名称转换为已部署的URL。
-
在打开控制台的情况下,在浏览器中进行部署和硬重新加载。