用 @types 前缀的包是什么?有什么用?

简介: 解决过 TypeScript 的项目大概都是从两个方向,Vue3 方向和 React Native 方向,而在 React Native 方向上我经常会遇到一个烦人的错误,这个问题的场景通常出现于 t

您可以在线查看完整的示例源代码

前言

解决过 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.
Try npm i --save-dev @types/types-study if it exists or add a new declaration (.d.ts) file containing declare module 'juejin-type-study';

PS: juejin-type-study 代指 npm 包,也是文章的例子

这个问题的场景通常出现于 ts 项目中引用包时会出现

// main.ts
import { util } from "juejin-type-study";

util();

PS: ts 指代 TypeScript

IMG

问题起因

ts 作为一个有类型的语言,在 .ts 文件引用包时,默认时必须要有类型声明的,不能是 any,而 ts 对于包(module)的类型声明要求为提供 .d.ts,否则就要在 tsconfig.json 中声明

那么就有一个问题了,ts 是怎么找到包/模块的类型声明的?

TS 寻找类型规则

ts 对于包/模块的声明寻找规则如下

  1. TypeScript 编译器先在当前编译上下文找模块的定义
  2. 如果找不到,则会去 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.jspackage.json

IMG

// main.js
export const util = () => {
  console.log("Hello World");
};

创建 .d.ts

之前的 ts 给出一个警告中包含一个解决方案,其中如下

Try npm i --save-dev @types/types-study if it exists or add a new declaration (.d.ts) file containing declare 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 的模板可以查看文档

创建之后就不会再报错了,如下

202212182214143.png

@types 本质上也是一样,ts 会自动帮我们识别 .d.ts 的位置,默认是根目录和 /node_modules/@types/[libname]/index.d.ts

IMG

注意,VS Code 对于类型提示和警告似乎有缓存,如果将 .d.ts 迁移位置后仍然报错可以尝试删除模块引用重新输入

参考资料

  1. types 和 @types 是什么? - lucifer
  2. Module .d.ts - .d.ts Templates - TypeScript Doc
相关文章
|
1月前
|
Java
java包装器类型
java包装器类型
17 0
|
6月前
|
安全 开发工具 iOS开发
.framework类型的静态库和.a类型的静态库的优缺点及.framework类型的静态库zip压缩后解压后头文件丢失问题
.framework类型的静态库和.a类型的静态库的优缺点及.framework类型的静态库zip压缩后解压后头文件丢失问题
37 0
|
JSON 数据格式 Python
24.从入门到精通:__name__属性 dir() 函数 标准模块 包 从一个包中导入*
24.从入门到精通:__name__属性 dir() 函数 标准模块 包 从一个包中导入*
|
编译器
VS2022编译GDAL库报错: LINK : error LNK2001: 无法解析的外部符号 _OSRValidate _OGR_G_GetPointCount _OGRRegisterAll
VS2022编译GDAL库报错: LINK : error LNK2001: 无法解析的外部符号 _OSRValidate _OGR_G_GetPointCount _OGRRegisterAll
474 0
|
JSON Go 数据格式
golang project 不显示文件夹 或者某个包明明能 import 但就是 import 不进来,提示Unresolved reference
golang project 不显示文件夹 或者某个包明明能 import 但就是 import 不进来,提示Unresolved reference
|
Dart
Dart之dynamic(任意类型)
Dart之dynamic(任意类型)
90 0
Dart之dynamic(任意类型)
|
Go
Go基础:路径、文件名和包名的关系
Go基础:路径、文件名和包名的关系
740 0
Go基础:路径、文件名和包名的关系
|
存储 安全 Android开发
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表文件格式 | 头文件 数据格式 | 全局字符串池 数据格式 | 包数据 数据格式 | 包头 数据格式 )(二)
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表文件格式 | 头文件 数据格式 | 全局字符串池 数据格式 | 包数据 数据格式 | 包头 数据格式 )(二)
311 0
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表文件格式 | 头文件 数据格式 | 全局字符串池 数据格式 | 包数据 数据格式 | 包头 数据格式 )(二)
|
存储 Android开发 数据格式
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表文件格式 | 头文件 数据格式 | 全局字符串池 数据格式 | 包数据 数据格式 | 包头 数据格式 )(一)
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表文件格式 | 头文件 数据格式 | 全局字符串池 数据格式 | 包数据 数据格式 | 包头 数据格式 )(一)
244 0
【Android 安装包优化】资源混淆 ( resources.arsc 资源映射表文件格式 | 头文件 数据格式 | 全局字符串池 数据格式 | 包数据 数据格式 | 包头 数据格式 )(一)
|
缓存 Java 程序员
Java - 为什么命名 interface 时不推荐添加 I 前缀?
Java - 为什么命名 interface 时不推荐添加 I 前缀?
589 0