如何从TypeScript中使用npm模块?
如何从TypeScript中使用npm模块?
我正在尝试使用TypeScript。在Hello World阶段,它运行良好。我现在正在尝试使用一个npm模块:
index.ts
=
import _ = require('lodash') console.log(_.toUpper('Hello, world !'))
这不起作用:
tsc index.ts
->无法找到模块'lodash'。(2307)
node-ts index.js
->无法找到模块'lodash'。(2307)
查看TypeScript文档和谷歌没有帮助。其他S/O问题要么没有答案(here和here),要么与此无关。
要素:
- typescript 1.8最新版本
- 是的,lodash已经安装
npm i --save lodash
并存在于我的文件系统中(已检查) - 我还执行了
typings i --save lodash
- 变体
import * as _ from 'lodash'
或const _ = require('lodash')
也不起作用 - 我尝试根据其他答案中的建议调整了tsconfig.json选项
"moduleResolution": "node"
和"module": "commonjs"
,仍然不起作用
我们如何在TypeScript中使用npm包?
问题的出现原因是,当从npm导入模块时,如果没有获取到类型声明文件(typings),tsc命令会报错找不到所需的模块(即使转译后的js实际上是可以工作的)。
解决方法有以下几种:
1. 如果有类型声明文件并且没有使用tsconfig.json文件,可以使用reference
来导入类型声明文件,并进行模块导入。
///import * as _ from 'lodash'; console.log(_.toUpper('Hello, world !'));
2. 如果使用了tsconfig.json文件,需要确保已经包含了类型声明文件(或者没有排除),然后按照上面的示例进行模块导入。
3. 当没有可用的类型声明文件时,有两种选择:在一个.d.ts
文件中编写自己的类型声明,或者忽略库的类型检查。
- 完全忽略类型检查(不推荐的方式),可以将导入的库赋值给一个any
类型的变量。
const _: any = require('lodash'); console.log(_.toUpper('Hello, world !'));
此时,tsc
命令会报错require
不存在,可以提供node
的类型声明文件,或者使用declare
关键字来消除错误。
以上是关于如何从TypeScript中使用npm模块的解决方法。需要注意的是,上述答案中提到的解决方法可能已经过时,建议查看其他答案或者参考最新的解决方案。
问题的出现原因:在使用TypeScript消耗npm modules时,可能会出现缺少Declaration Files的情况。
解决方法:安装Declaration Files,并进行正确的导入和使用。
具体解决步骤如下:
1. 安装Declaration Files:
npm install --save lodash
npm install --save /lodash
2. 进行导入:
import _ from 'lodash';
如果导入的模块有多个导出,可以使用以下方式导入:
import { Express, Router } from 'express';
如果导入的模块没有默认导出,需要使用以下方式导入:
import * as http from 'http';
为什么我们需要使用* as _
而不仅仅是_ from 'lodash'
,就像在ES6代码中一样?
很好的问题。在这种情况下,使用import _ from 'lodash';
更好。我已经更新了我的答案,展示了不同的导入方式以及为什么要使用它们。
如果模块没有默认导出,就需要使用* as _
。tsc编译器会对此进行警告。
“没有默认导出”是什么意思?这是否意味着没有定义Typescript类型(例如导入一个普通的JavaScript模块)?我对JS/Typescript还不熟悉....
“没有默认导出”意味着模块没有export default <...>
语句。请参阅TypeScript模块文档的“默认导出”部分。
问题的出现原因是,在使用TypeScript消费npm模块时,需要有关于包代码的类型信息(也称为“类型声明文件”或“typings”),否则将失去使用TypeScript的意义。解决方法主要有以下几种:
解决方案0:如果模块已经提供了类型声明文件,可以在package.json中找到类似于以下内容的行:
"typings": "dist/index.d.ts"
这表示该模块已经启用了TypeScript。如果是这种情况,那就没问题了。如果不是,继续往下看。
解决方案1:使用DefinitelyTyped中的社区贡献的类型声明文件。假设要为一个名为“foo”的模块使用类型声明文件,可以尝试以下命令:
npm add -D /foo
如果命令执行成功,那么你现在就有了类型声明文件,可以使用该模块了。如果npm报错找不到该模块,则继续往下看。
解决方案2:提供自定义的类型声明文件(可以选择不费力的方式)。
1. 在项目的根目录下创建一个名为“typings-custom”的文件夹。
2. 在tsconfig.json中引用该文件夹的内容:
"include": [
"./typings-custom/**/*.ts"
]
3. 创建一个名为“foo.d.ts”的文件(其中foo为模块的名称),并在文件中添加以下内容:
declare module 'foo'
你的TypeScript代码现在应该可以编译通过了,尽管没有类型信息(TypeScript会将foo模块的类型视为"any")。
你也可以尝试自己编写类型信息,可以查看官方文档或DefinitelyTyped的示例。如果你编写了类型信息,可以考虑直接将其贡献给该模块(解决方案0,如果模块作者接受)或DefinitelyTyped(解决方案1)。
另外,我们还可以在一个文件中声明多个自定义类型。不需要多个文件(也许?)。
Step 2. "在tsconfig.json中引用该文件夹的内容"会导致以下错误:Unknown compiler option 'include',实际上它不是一个编译器选项,它应该是`compilerOptions`的同级属性。
当我添加了include行后,TS不再识别React本身。错误信息为:This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.尽管我的TSConfig中有`"esModuleInterop": true`。
我认为解决方案3应该参考stackoverflow.com/a/55396763/2290413。