typescript 配置精讲 | moduleResolution

2024-05-27 08:52

本文主要是介绍typescript 配置精讲 | moduleResolution,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

大家好,我是17。

moduleResolution 是 typescript 模块配置中最重要的一个配置,所以 17 单拿出来讲一下。如果你去看文档还是挺复杂的,但如果不去深究细节,只想知道如何配置还是很简单的。3 分钟就能学会。

moduleResolution 的作用

moduleResolution 是用来解决如何查找文件的。比如

import name from 'iam17'

这条语句首先要做的就是把 iam17 对应的文件找到。如何查找文件受到 moduleResolution 配置的景响。

配置 moduleResolution

为打包器量身定做的 Bundler 选项

前端主要的场景是使用 typescript 做类型检查,并不输出内容。把 ts 转换成 js 的工作是由打包工具来完成的。这种情况下,把 moduleResolution 设置为 Bundler 就行了。Bundler 的原意就是打包器的意思。现在流行的打包器 webpack,vite 等支持的特性,Bundler 选项都支持。Bundler 选项就是为打包工具量身定做的。

专为 node 开发的 node16 选项

还有一部分的前端开发场景是进行 nodejs 开发。最终的代码的运行环境是 node 环境。这个时候把 moduleResolution 设置为 node16 就行了。

其它的选项

之所以剩下的都归为其它,是因为其它的使用场景很少,了解即可。

如果不得不使用 node 老版本,只能用 Node10 选项了,也可以用 Node。 Node10 和 Node 是一个意思,可以认为是一个选项有两个名字。ts 5.0 中,把 Node rename 成了 Node10,为了让原来的配置文件有效,保留了 Node 选项。

NodeNext 目前等同于 Node16。如果之后有 Node17,那么 NodeNext 就等同于 Node17。NodeNext 总是指向 node 环境的最新配置。

还有一个选择 Classic。Classic 虽然还在出镜,但也仅限于名字本身了,几乎不会有使用的场景。ts 已经明确说明,在下个版本会移出 Classic 选项。各们同学就当他不存在就好。

到这里,如何配置 moduleResolution 就讲完了。这对于 99% 的同学来说已经够用了。但是作为 1% 的同学,还想有更高的追求,就需要了解一下配置的细节。比如 17 想写一个打包工具,不知道 ts 执行的细节 ,怎么和 ts 配合啊。就算没有写工具的需求,如果哪天 ts 报错了,总得知道怎么修改配置吧。还有一个理由,如果你去面试,问你 moduleResolution 的执行细节呢?虽然开发的时候用不到,但面试的时候不都是要求你会靠火箭的吗?其实呢,面试官也知道平时不用,这只是个加分项,可能是想知道你是不是爱学习。所以同学们,系好安全带,准备出发吧!

说到细节,首先要知道这些选项都是怎么来的,然后再理解这些选项都做了什么就水到渠成了。还要认清 TypeScript 的定位,TypeScript 是为了让 js 更加强大,更加好用,TypeScript 最终还是要编译成 js 才能用。所以在各个历史时期,ts 都是配合 js。对于解析文件路径,TypeScript 几乎总是从其输出JavaScript 文件的角度来考虑这些问题,而不是从其输入TypeScript(或 JavaScript!)文件的角度来考虑这些问题。

在解释这些查找细节之前,首先需要了解一下,ts 是如何自动补充文件名扩展名,自动解析文件夹模块的。

文件扩展名自动补充

import name from './iam17'
import name from './iam17.js'

两条语句一条带扩展名,一条不带,对于 ts 来说,.js 扩展名可以省略,

不带扩展名,和带 .js 扩展名, ts 查找相关文件策略是一样的。

ts 拿到文件名 iam17 后,会查找相关的文件。分两步

  1. 查找相关的类型文件,看有没有 iam17.ts,iam17.tsx,iam17.d.ts
  2. 查找相关的 js 文件,看有没有 iam17.js,iam17.jsx

ts 是会优先查找类型文件,如果没有类型文件才去查找 js 文件。

如果扩展名是 mjs

import name from './iam17.mjs'

ts 要查找的文件有所不同

  1. 查找相关的类型文件,看有没有 iam17.mts,iam17.d.mts
  2. 查找 iam17.mjs

如果扩展名是 cjs

import name from './iam17.cjs'

ts 要查找的文件为

  1. 查找相关的类型文件,看有没有 iam17.cts,iam17.d.cts
  2. 查找 iam17.cjs

如果只有类型文件,没有 js 文件,ts 会报错吗?答案是不会。

目录模块

还是这条语句

import name from './iam17'

如果不带后缀名,ts 除了查找相关的文件外,还会检查 iam17 是不是一个文件夹。

如果 iam17 是一个文件夹,会解析根目录下的 package.json 文件。

  1. 解析 package.json 中的 types
  2. 解析 package.json 中的 typings
  3. 解析 package.json 中的 main

如果上面 3 步都找不到,查找根目录下的 index.ts,index.d.ts,index.tsx,index.js。

总的来说,也是先查找类型文件,找不到类型文件,再查找 js 文件。

typings 是历史遗留,不要使用

types 和 typings 直接指定类型文件。 main 指定 js 文件,ts 找到 main 指定的 js 文件后还会根据补充文件扩展名的规则查找类型文件。

有了 文件扩展名补充 和 文件夹模块 这两个基础知识,再理解 ts 的文件查找逻辑就容易多了。

选项 Classic

Classic 是第一个 moduleResolution 选项。因为已经几乎没有使用的场景,所以直接忽略。

选项 Node

当 nodeJs 的 commonJs 模块标准逐渐成为主流标准的时候,ts 适时的给出 node 选项。听这个名字就知道,ts 查找文件的方式和 nodeJs 差不多。因为 ts 有类型,所以在查找上,ts 是优先查找类型文件,其次才是查找实际的 js 文件。查找逻辑分下面几种

  1. 绝对路径
  2. 相对路径
  3. 安装包路径
  4. node 核心模块

绝对路径

以 / 开头的就是绝对路径。绝对路径是磁盘上的绝对物理路径。

import name from '/root/home/iam17'

ts 会判断 iam17 是文件夹还是文件,如果是文件夹就按文件夹模块查找,如果是文件,就按文件扩展名补充查找。

如果后面有扩展名,不会执行文件模块查找。

相对路径

项目内的模块必须用 前导 './' 或 '../' 来指示相对路径。

import name from './iam17'

ts 会以当前文件为基准进行查找。ts 会判断 iam17 是文件夹还是文件,如果是文件夹就按文件夹模块查找,如果是文件,就按文件扩展名补充方案查找。

如果后面有扩展名,不会执行文件模块查找。

安装包路径

如果没有前导 '/''./' 或 '../' 来指示文件,该模块会从 node_modules 文件夹加载。

import name from 'iam17'

ts 还是会优先查找 iam17 的类型声明,然后才是查找 js 文件。类型声明会先从模块中查,查不到,再到 @types/iam17 中查。

在模块中查找过程和 文件夹模块 查找逻辑一样。

和文件夹模块不同的是,ts 查找 node_modules 中的模块首先会在当前目录查,如果查不到,要到上级的 node_modules 目录查,直到根目录下的 node_modules。

node 选项还可以随意查找子路径 比如 import name from ‘iam17/work’

node 核心模块

ts 并不认识哪些是 node 核心模块。ts 会当普通模块处理,解决办法就是安装 node 类型声明

 npm install @types/node

typesVersions

如果你需要在多个 ts 版本中进行开发,可能需要多个版本的声明文件,因为不同版本 ts 的声明文件可能是不兼容的。

{"name": "pkg","version": "1.0.0","types": "./index.d.ts","typesVersions": {">=3.1": {"*": ["ts3.1/*"]}}
}

了解下即可,一般不会遇到需要配置 typesVersions 的情况。这种只是用来应急的,如果把它当作常态,你需要反思下项目管理了。

选项 Node16,NodeNext

typeScript 4.7 增加了 Node16,NodeNext 这两个选项,因为这个时期 ESM 模块已经成为标准。和 Node 选项相比,在解析路径方面新增加两条规则,删除了两条规则。

增加了 package.json “exports”

当 moduleResolution 设置为 node16, nodenext, or bundler,并且 resolvePackageJsonExports(tsconfig.json 中的配置)没有设置为 false,ts 会解析 package.json 的 “exports” 信息。

当 moduleResolution 设置为 node16, nodenext, or bundler 的时候,resolvePackageJsonExports 默认是开启的。为什么 ts 要增加 resolvePackageJsonExports 这个配置。原因是为了照顾老项目。
resolvePackageJsonExports 了解一下即可,一般不需要手动修改它。

关于 exports 详细规范大家可以去 node 官网上去查,17 贴心的直接给出地址 点这里查看 export 详情

在 node exports 规范的基础上,ts 还会查找 types ,default 两个用户导出条件。关于用户导出条件可以看我写的上一篇文章 typescipt 配置精讲 | customConditions

增加了 package.json “imports” and self-name imports

当 moduleResolution 设置为 node16, nodenext, or bundler,并且 resolvePackageJsonImports(tsconfig.json 中的配置)没有设置为 false,ts 会解析 package.json 的 “exports” 信息。

当 moduleResolution 设置为 node16, nodenext, or bundler 的时候,resolvePackageJsonImports 默认是开启的。resolvePackageJsonImports 也是为了照顾老项目设置的。

resolvePackageJsonImports 了解一下即可,一般不需要手动修改它。

详情可以参阅 ts 文档,点这里

简单来说 #imports 相当于是给子路径起了一个别名。先查找 package.json,找到 imports,再找到相应的 key,根据 key 的内容去查找类型。了解下即可。

删除了文件扩展名自动补充

因为 在 node 的 ESM 模块中,引用模块是必须要写文件扩展名。

import name from './iam17'

这样写会报错,必须要补全后面的 .js,这样写才行:./iam17.js

删除了目录模块的支持

设置为 node16 后,ts 不再进行文件夹模块的尝试。

node 在 ESM 模块下,找不到文件就会报错,不再做其它尝试。 ts 也只是查找相关的类型文件,找不到就报错。

17 觉得 ESM 要求明确写出扩展名是个好事,这样会大大简化查找文件的逻辑。但是,这只能是一个理想,因为目前已经存在的老项目都是没写扩展名的。这就导致 Node16 只能在新项目里用。很多同学都习惯了不写扩展名,现在让他们写扩展名,会觉得不习惯。最后的结果就是新项目也没人愿意用 Node16。

Bundle 选项

由于 Node16 让很多同学不习惯,所以 ts 在 5.0 又推出了 Bundle 选项。反正有打包工具打底,Bundle 选项索性支持所有特性,把文件扩展名自动补充,目录模块的规则又加了回来,也支持 “imports”,“exports"。

到这所有选项就讲完了,可是路径解析的故事还没有结束,小伙伴们再坚持一下,马上到终点了。

虽然本篇文章讲的是 moduleResolution 配置,但如果不讲 paths,baseUrl,typeRoots,types 和全局类型声明,ts 的路径解析逻辑是不完整的。

paths,全局路径映射

如果每次都写相对路径还是很不方便的,这时可以用 paths 简化。

{"compilerOptions": {"module": "esnext","moduleResolution": "bundler","paths": {"@/*": ["./src/*"]}}}

有了这个配置后,就可以这样写路径了,无论是在哪个文件里

import name from '@/iam17'

无论是哪个文件里,都会被解析成到项目根目录/src/iam17。这个配置还是挺常用的,实际项目里,一般都会加上这样的配置。

更多 paths 的详情 点这里查看

注意:如果不打算用打包工具,不要用 paths 配置,ts 不会对 path 设置的映射做转换

baseUrl

这是历史遗留的产物,不要使用,同学们当它不存在就好。

如果想了解一下详情,可以 看这里

typeRoots

ts 首先会查找类型文件,在模块里查不到会到 @types 目录去查,这个@types 就是默认的 typeRoots,一般不需要修改 typeRoots, 了解下就好。查看详情

types

types 相当于一个白名单,只有加入白名单的模块, ts 才会到 typeRoots 中查找。types 限制了 ts 在 typeRoots 中的查找范围。一般也不会用到这个配置,了解下就好。里查看详情

全局类型声明

在项目中,如果在 ts , .d.ts 文件中没有 import ,export 语句,文件中定义的类型就会成为全局的类型。以这种方式定义的模块全局可用。

用 declare module 来定义模块。这个定义是全局的。

在项目中添加 index.d.js

declare module 'iam17' {const name: stringexport default { name }
}

在项目中的任意 .ts 文件中都可以解析到 iam17 模块

image.png

本文到这里就结束了,撤花~

参考

  • CommonJS 模块
  • ECMAScript 模块
  • TS Modules - Reference

番外

17 觉得,随着时间的推移,Node,Node10 两个选项可能会被移除。就和 Classic 的结局一样,它们都只是过渡值,最终肯定是 ESM 模块一统天下。

对于 ESM 规定必须写文件后缀名这事,17 是非常赞同的。只是使用者不会管你后面的逻辑有多复杂,用着爽就好。所以虽然规范不再支持,但打包工具依然会把这个逻辑补充上。如果一直这样,不知道后面规范会不会把自动补后缀名的逻辑再加回来。

如果不考虑历史原因,js 模块路径解析也并不复杂。 但 js 曾经的模块方案终究还是留下了自己的印记。

17 花了两天,周末都在写。本来打算半天就写好了,但实际上内容特别繁杂。如果你一直扎进文档,可能会越看越晕,所以 17 写这篇文章进行梳理。关于解析路径的内容很多,如果都放上,那就成一本书的规模了。多数内容文档上都有,没必要搬来搬去的。17 尽量压缩内容,但保证所有关键点都写到,让大家在最短的时间内对 ts 路径解析有一个整体的把握。

这篇关于typescript 配置精讲 | moduleResolution的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1007016

相关文章

Linux 安装、配置Tomcat 的HTTPS

Linux 安装 、配置Tomcat的HTTPS 安装Tomcat 这里选择的是 tomcat 10.X ,需要Java 11及更高版本 Binary Distributions ->Core->选择 tar.gz包 下载、上传到内网服务器 /opt 目录tar -xzf 解压将解压的根目录改名为 tomat-10 并移动到 /opt 下, 形成个人习惯的路径 /opt/tomcat-10

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

IDEA配置Tomcat远程调试

因为不想把本地的Tomcat配置改乱或者多人开发项目想测试,本文主要是记录一下,IDEA使用Tomcat远程调试的配置过程,免得一段时间不去配置到时候忘记(毕竟这次是因为忘了,所以才打算记录的…) 首先在catalina.sh添加以下内容 JAVA_OPTS="-Dcom.sun.management.jmxremote=-Dcom.sun.management.jmxremote.port

Steam邮件推送内容有哪些?配置教程详解!

Steam邮件推送功能是否安全?如何个性化邮件推送内容? Steam作为全球最大的数字游戏分发平台之一,不仅提供了海量的游戏资源,还通过邮件推送为用户提供最新的游戏信息、促销活动和个性化推荐。AokSend将详细介绍Steam邮件推送的主要内容。 Steam邮件推送:促销优惠 每当平台举办大型促销活动,如夏季促销、冬季促销、黑色星期五等,用户都会收到邮件通知。这些邮件详细列出了打折游戏、

微信小程序开发必知必会:文件结构和基本配置

一、微信小程序基本文件结构 1.  project.config.json:项目的基本配置文件,包括项目名称、appid、项目目录、页面文件夹等。     {"setting": {"urlCheck": false,"es6": true,"postcss": true,"nodeModulesPath": "D:\\\\node_modules"},"appid": "wxd678e

【杂记-浅谈DHCP动态主机配置协议】

DHCP动态主机配置协议 一、DHCP概述1、定义2、作用3、报文类型 二、DHCP的工作原理三、DHCP服务器的配置和管理 一、DHCP概述 1、定义 DHCP,Dynamic Host Configuration Protocol,动态主机配置协议,是一种网络协议,主要用于在IP网络中自动分配和管理IP地址以及其他网络配置参数。 2、作用 DHCP允许计算机和其他设备通

Pycharm配置conda环境(解决新版本无法识别可执行文件问题)

引言: 很多小伙伴在下载最新版本的pycharm或者更新到最新版本后为项目配置conda环境的时候,发现文件夹目录中无法显示可执行文件(一般为python.exe),以下就是本人遇到该问题后试验和解决该问题的一些方法和思路。 一般遇到该问题的人群有两种,一种是刚入门对pycharm进行conda环境配置的小白(例如我),不熟悉相关环境配置的操作和过程,还有一种是入坑pycharm有段时间的老手

【zabbix】zabbix客户端配置

1、部署zabbix客户端 #zabbix 5.0 版本采用 golang 语言开发的新版本客户端 agent2 。#zabbix 服务端 zabbix_server 默认使用 10051 端口,客户端 zabbix_agent2 默认使用 10050 端口。systemctl disable --now firewalldsetenforce 0hostnamectl set-host

局域网内vue2 配置本地IP地址访问项目

在日常开发中同事可能需要访问你的前端项目,可以通过配置实现通过ip访问 一.首先找到config文件夹目录下的 index.js文件             将此处的host的值修改为0.0.0.0(即 host: 0.0.0.0) // Various Dev Server settings//host: 'localhost' //将localhost进行替换成 0.0.0.0host:

众所周知,配置即代码≠基础设置即代码

​前段时间翻到几条留言,问: “配置即代码和基础设施即代码一样吗?” “配置即代码是什么?怎么都是基础设施即代码?” 我们都是知道,DevOp的快速发展,让服务器管理与配置的时间大大减少,配置即代码和基础设施即代码作为DevOps的重要实践,在其中起到了关键性作用。 不少人将二者看作是一件事,配置即大代码是关于管理特定的应用程序配置设置本身,而基础设施即代码更关注的是部署支持应用程序环境所需的