前言
如果你在 TypeScript 中引入了一个纯 JavaScript 包,那很有可能会看到这样的报错:
Could not find a declaration file for module ‘@koumoul/vjsf/lib/VJsf’. ‘c:/*/node_modules/@koumoul/vjsf/lib/VJsf.js’ implicitly has an ‘any’ type.
Trynpm i --save-dev @types/koumoul__vjsf
if it exists or add a new declaration (.d.ts) file containingdeclare module '@koumoul/vjsf/lib/VJsf';
Vetur(7016)
问题剖析
最近我在编写管理界面,使用了 vuetify-jsonschema-form
库来生成表单,可惜这个库有各种缺点,其中之一就是没有提供 TypeScript 的类型声明。
当 import 一个没有类型声明的第三方库时,TypeScript 不知道 import 进来的东西是什么类型,只能偷偷地把它指定成 any 类型,这也就是我们常说的隐式 any(implicit any)。所有正常的前端项目都会禁止 implicit any 出现,所以就报错了。
如果你在网上搜索,网上的文章很可能会让你用这些方法:
- 关掉 implicit-any 的检查
- 在 import 语句上加上
// @ts-ignore
这些方法非常不推荐使用,因为这样一来我们就远离了 TypeScript 给我们的保护,给项目引入了定时炸弹。那么怎么办呢?有两种方法:
解决方案 1:安装官方的类型声明
一般来说,如果你用的是 lodash 这种大库,那么官方已经帮你写好类型声明了,只要按照这个库的官方文档,安装 @types/库名
这个库就行了。比如,使用 lodash 库的时候,只需要安装它的类型声明库:
npm install --save-dev @types/lodash
解决方案 2:使用 declare module
语法
但是,显然不是每个库都能有这种待遇。如果你用的是小库,而且官方文档里又没说怎么安装类型声明,那就只能自己动手了。
错误信息里面,有这样的一句话:
add a new declaration (.d.ts) file containing `declare module ‘@koumoul/vjsf/lib/VJsf’;
这是什么意思呢?根据官方文档,只需要在 TypeScript 的 .d.ts 文件中编写一个空的 declare module
,就能把环境包当作 any 类型引入,同时又不会触发 implicit any 报错。这个操作被文档叫做 Shorthand ambient modules,意为「快速引入环境包」:
那么实际使用时要怎么做呢?我们首先在项目的任意位置建立一个 js-modules.d.ts 文件,向里面填入如下内容:
declare module '【import 的第三方库名】';
接下来可以试着重启一下 IDE,看看报错是不是已经消除了。我们来尝试一下,用 declare module 声明了 vuetify-jsonschema-form
库,然后我们观察一下引入的变量类型:
可以看出,引入的模块变量确实是 any 类型,而且这样已经不算是隐式 any 了,所以不会报错。