您可以在线查看完整的示例源代码
前言
解决过 TypeScript
的项目大概都是从两个方向,Vue3
方向和 React Native
方向,而在 React Native
方向上我经常会遇到一个烦人的错误
Could not find a declaration file for module 'juejin-type-study'. 'd:/fe-project/nodejs/types-study/node_modules/juejin-type-study/main.js' implicitly has an 'any' type.
Trynpm i --save-dev @types/types-study
if it exists or add a new declaration (.d.ts) file containingdeclare module 'juejin-type-study';
PS: juejin-type-study
代指 npm
包,也是文章的例子
这个问题的场景通常出现于 ts
项目中引用包时会出现
// main.ts
import { util } from "juejin-type-study";
util();
PS: ts
指代 TypeScript
问题起因
ts
作为一个有类型的语言,在 .ts
文件引用包时,默认时必须要有类型声明的,不能是 any
,而 ts
对于包(module
)的类型声明要求为提供 .d.ts
,否则就要在 tsconfig.json
中声明
那么就有一个问题了,ts
是怎么找到包/模块的类型声明的?
TS 寻找类型规则
ts
对于包/模块的声明寻找规则如下
TypeScript
编译器先在当前编译上下文找模块的定义- 如果找不到,则会去
node_modules
中的@types
(默认情况,目录可以修改,后面会提到)目录下去寻找对应包名的模块声明文件
说实话 TypeScript
的文档真的不怎样,虽然有中文文档,但文档整个的逻辑很乱,知识点东一块西一块,找起来很麻烦,像此类的寻址规则,通常文档会给出一个很严谨的描述,比如 Node.js
的模块寻址,但我在 ts
的文档里愣是半天没找着,等我找到了会更新一个更严谨的规则
作用
.ts
文件和 .js
文件不一样,对于 node.js
环境中 .js
有自己的模块寻址规则,而对于 ts
环境中 .ts
文件中的模块就是类型声明,ts
依靠类型声明来实现自己的功能,而 @types
其实就是类型声明的集中仓库,为 ts
项目中的引用提供类型说明
为什么需要 @types
这个目录?原因是过去很多模块/包是用的纯 JS
写的,没有类型声明,ts
就无法给到自动补全和智能提示等功能
下面就通过解决之前提出过的问题来解释实际中的 @types
是咋用的
创建 Module
在此之前我们需要一个模块来作为项目中引用的 Module
,毕竟 @types
中包含的就是 Module
的类型声明
那没有 npm
包怎么办?需要去 npm
网站里创建一个吗?
实际上并不需要,了解过 Node.js
关于模块的寻址规则就可以直接在 node_modules
目录下伪造一个模块,具体原理可以参考这篇文章
在 node_modules
中创建一个 juejin-type-study
的目录,里面只需要包含两个文件,main.js
和 package.json
// main.js
export const util = () => {
console.log("Hello World");
};
创建 .d.ts
之前的 ts
给出一个警告中包含一个解决方案,其中如下
Trynpm i --save-dev @types/types-study
if it exists or add a new declaration (.d.ts) file containingdeclare module 'juejin-type-study';
里面提到可以创建一个 .d.ts
文件,包含 declare module 'juejin-type-study';
就可以解决这个问题
实际操作就是在根目录下随便取个名字创建 .d.ts
,通常为缺失类型声明的模块名称,如下
declare module 'juejin-type-study' {
export function util(): void;
}
Module .d.ts
的模板可以查看文档
创建之后就不会再报错了,如下
而 @types
本质上也是一样,ts
会自动帮我们识别 .d.ts
的位置,默认是根目录和 /node_modules/@types/[libname]/index.d.ts
注意,VS Code
对于类型提示和警告似乎有缓存,如果将 .d.ts
迁移位置后仍然报错可以尝试删除模块引用重新输入