typescript 配置精讲 | moduleResolution

news2024/12/24 22:04:20

大家好,我是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: string
    export default { name }
}

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

image.png

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

参考

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

番外

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1700515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

neo4j开放远程连接

注:本博客所用neo4j版本为社区5.12版 第一步:修改neo4j配置文件 首先找到neo4j的安装位置,点击进入conf文件夹,随后点击neo4j.conf文件,在“Network connector configuration”下面的单元中找到server.default_liste…

奥枫软件Java要个16K遇到地狱级难度,醉了。。。

我只能说地狱难度,没绝对把握就别去了。我凭借前辈的经验,和当时天时地利人和,六道题答得很不错,但还是没通过。我有备而来都没过,现场写那些应该都是白忙活了。 一面 1,分割一个整数。如123,结…

贪心-AcWing 125. 耍杂技的牛-XMUOJ蒙德冒险者的游戏

题目 思路 每头牛的危险值 他前面牛的w(重量值)之和 - 自身的s(强壮值) 要使每头牛的危险值最小,根据贪心思想: 自身w值越大应该放到底部(即减小上述式中的被减数) 自身s值越大应该放到底部(即增大上述式中的减数&…

KingbaseES数据库union的用法

数据库版本:KingbaseES V008R006C008B0014 文章目录如下 1. union的概念 2. union的语法 3. union的用法 3.1. 去重(union) 3.2. 不去重(union all) 3.3. 聚合运算 3.4. 异常案例 1. union的概念 UNION 是结构…

ClickHouse架构概览 —— Clickhouse 架构篇(一)

文章目录 前言Clickhouse 架构简介Clickhouse 的核心抽象列和字段数据类型块表 Clickhouse 的运作过程数据插入过程数据查询过程数据更新和删除过程 前言 本文介绍了ClickHouse的整体架构,并对ClickHouse中的一些重要的抽象对象进行了分析。然后此基础上&#xff0…

揭秘OS模块:文件与文件夹的遍历艺术

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、引言 二、os.listdir():当前目录的扫描者 三、os.walk():文件系…

深度学习——自己的训练集——训练模型(CNN)

训练模型 1.导入必要的库2.加载类别名称3.创建标签映射字典4.加载图像数据和对应的标签5.构建和编译CNN模型6.训练模型7.保存训练好的模型 1.导入必要的库 导入处理数据和训练模型时需要的库 os: 这个模块提供了与操作系统交互的功能,比如文件和目录操作。 cv2: 这…

如何选择优质的气膜体育馆工程服务商—轻空间

随着现代生活的便利化和时代感的增强,气膜体育馆成为越来越多人的选择。这种美观实用的建筑在学校、社区和体育中心等地广泛应用。许多投资者和客户都有意建造气膜体育馆,但在选择工程服务商时,往往面临困惑。以下几点将帮助您做出明智的选择…

grafana大盘展示node_expod节点

node_expod添加lables标签 Prometheus查询 语句查询 node_exporter_build_infografna添加变量查询 正常有值 切换其他的是有值的 我的报错原因 因为有多个数据源,我选择错了,因为修改的lable标签是其他数据源,所以获取不到 查询语句 我的变量是 $app node_filesyste…

【优选算法】位运算 {位运算符及其优先级;位运算的应用:判断位,打开位,关闭位,转置位,位图,get lowbit,close lowbit;相关编程题解析}

一、位运算符及其优先级 我们知道,计算机中的数在内存中都是以二进制形式进行存储的 ,而位运算就是直接对整数在内存中的二进制位进行操作,因此其执行效率非常高,在程序中尽量使用位运算进行操作,这会大大提高程序的性…

SpringBoot 上传文件示例

示例效果&#xff1a; 前端代码&#xff1a; <html> <head><title>上传文件示例</title></head> <body> <h2>方式一&#xff1a;普通表单上传</h2> <form action"/admin/upload" method"post" enctyp…

【Python】 Django 框架如何支持百万级日访问量

基本原理 Django 是一个高级的 Python Web 框架&#xff0c;它鼓励快速开发和干净、实用的设计。Django 遵循 MVC&#xff08;模型-视图-控制器&#xff09;设计模式&#xff0c;允许开发者通过编写更少的代码来构建高质量的 Web 应用程序。Django 自带了许多内置功能&#xf…

Python-opencv通过距离变换提取图像骨骼

文章目录 距离变换distanceTransform函数 距离变换 如果把二值图像理解成地形&#xff0c;黑色表示海洋&#xff0c;白色表示陆地&#xff0c;那么陆地上任意一点&#xff0c;到海洋都有一个最近的距离&#xff0c;如下图所示&#xff0c;对于左侧二值图像来说&#xff0c;【d…

嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻嘻

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

golang中的md5、sha256数据加密文件md5/sha256值计算步骤和运行内存图解

在go语言中对数据计算一个md5&#xff0c;或sha256和其他语言 如java, php中的使用方式稍有不同&#xff0c; 那就是要加密的数据必须通过流的形式写入到你创建的Hash对象中。 Hash数据加密步骤 1. 先使用对应的加密算法包中的New函数创建一个Hash对象&#xff0c;(这个也就是…

linux经典定时任务

在使用时记得替换为自己的脚本路径。请在相应的脚本第一行加上#!/bin/bash&#xff0c;否则脚本在定时任务中无法执行。 1、在每天凌晨2点执行 0 2 * * * /bin/sh bashup.sh 2、每天执行两次 下面的示例命令将在每天上午5点和下午5点执行。您可以通过逗号分隔指定多个时间戳…

vue中的$nextTick和过渡与动画

一.vue中的$nextTick 简述与用法&#xff1a;这是一个生命周期钩子 1.语法&#xff1a;this.$nextTick(回调函数) 2.作用&#xff1a;在下一次DOM更新结束后执行其指定的回调 3.什么时候用&#xff1a;当修改数据后&#xff0c;要基于更新后的新dom进行某些操作时&#xff0c;…

vue.js基础组件4--下

1.动态组件 1.定义动态组件 利用动态组件可以动态切换页面中显示的组件。使用<component>标签可以定义动态组件&#xff0c;语法格式如下。 <component is"要渲染的组件"></component>上述语法格式中&#xff0c;<component>标签必须配合i…

爬山算法全解析:掌握优化技巧,攀登技术高峰!

一、引言 爬山算法是一种局部搜索算法&#xff0c;它基于当前解的邻域中进行搜索&#xff0c;通过比较当前解与邻域解的优劣来更新当前解&#xff0c;从而逐步逼近最优解。本文将对爬山算法进行详细的介绍。 二、爬山算法简介 爬山算法是一种基于贪心策略的优化算法&#xff…

Modular military character

角色具有31个模块化骨架网格,每个模块具有多个蒙皮: 3个头(4skins) 3件衬衫(9skins) 3条裤子(9skins) 3只靴子(9skins) 7件战术背心(3skins) 4只手和手臂(2skins) 3顶帽子和头盔(9skins) 2个背包(3skins) 3支步枪(3skins) 模块允许您组装超过200万个不同的…