typescipt 配置精讲 | customConditions你一定没用过 ts 的这个配置:customCondi
大家好,我是 17。
在看 typescirpt 文档的时候发现有这样一个配置 customConditions。 文档中是这样说的 原文链接。感觉好像是看明白了,但实际上,当你实践的时候,并不容易看到效果。为了看到效果,还需要一些知识做辅助。
node 模块系统
这里是 node 模块系统的文档,原文链接。文档中内容较多,我把 customConditions 配置相关的内容再介绍一下。
子路径导出
当使用 "exports" 字段时, "."子路径用来定义主入口点。
{
"exports": {
".": "./index.js",
"./submodule.js": "./src/submodule.js"
}
}
比如模块名叫 ”iam17“,对于上面的配置,可以这样导入 exports 定义的 "."
import iam17 from 'iam17'
iam17 模块还得有默认导出才行
导入 exports 定义的 "./submodule.js"
import submodule from 'iam17/submodule.js';
条件导出
条件导出提供了一种根据特定条件映射到不同路径的方法。子路径导出和条件导出相当于是两重 if
// 判断子路径
if(path){
// 判断条件
if(contidtion){
// 根据 path 和 contidtion 决定导出的内容
}
}
比如在子路径的基础上,再加上条件
"exports": {
".": {
"import": "./baz.mjs",
"require": "./biz.mjs"
}
}
import iam17 from 'iam17
这条语句会命中"import": "./baz.mjs"
const iam17 = require('iam17)
这条语句会命中"require": "./biz.mjs"
node 系统中内置的条件有下面 5 个,"node-addons","node","import","require","default" 。除了系统内置的,还可以自定义条件,文档中叫 用户条件。
node 文档只有一句命令,如果你只看文档,可能还是跑不起来。17 再解释一下。
看下 ts 文档中的例子
"exports": {
".": {
"my-condition": "./foo.mjs",
"node": "./bar.mjs",
"import": "./baz.mjs",
"require": "./biz.mjs"
}
}
"my-condition" 就是自定义条件。自定义条件必须放在最前面。否则即使你在命令行中指定了node --conditions=my-condition
也没有用。这与用户条件查找规则有关。
node 按顺序 查找符合要求的条件,找到第一个就结束查找。
如果你引用模块的代码是这样的 import iam17 from 'iam17
下面配置的用户条件无法命中
"exports": {
".": {
"node": "./bar.mjs",
"my-condition": "./foo.mjs",
"import": "./baz.mjs",
"require": "./biz.mjs"
}
}
因为 node 条件也可以用作 import 语句的导出。但如果你把 require 条件放在 my-condition 条件之前是没有关系的。
所以 node --conditions=my-condition
只是让 my-condition 有了参选的资格,能不能选中还要看配置中的优先级。越靠前优先级越高。
node 中的自定义条件导出的使用场景
自定义导出是可以有多个的。自定义导出可以提供灵活性。可以通过编程的方式根据不同的条件使用不同的导出。
typescirpt 使用自定义导出配置
我们先看下官方的例子
{
"compilerOptions": {
"target": "es2022",
"moduleResolution": "bundler",
"customConditions": ["my-condition"]
}
}
文档中说 moduleResolution 换成 node16
, nodenext
也是可以的。文档并没有解释为什么这三个值可以,而其它的值为什么不可以。17 来补充一下。
moduleResolution 隐含指出代码将要运行在什么样的环境中。
条件导出是 Node v14.9.0 才定稿的,所以 Node(Node10 和 Node 的含义一样)肯定是不行的。既然条件导出是 Node 搞出来的。那么其它的可选值肯定是不行的。
为什么 "Bundler" 又行了呢?因为 "Bundler" 隐含指出代码的的环境是 “打包工具”。 打包工具当然可以理解这个配置。(不理解也可以让他理解)
在 typescirpt 中使用 customConditions 实践
环境准备,需要自己做一个 node 模块,为了叙述方便,这个模块命名为 'iam17',具体就不展开说了,配置文件就用官方的例子
"exports": {
".": {
"my-condition": "./foo.mjs",
"node": "./bar.mjs",
"import": "./baz.mjs",
"require": "./biz.mjs"
}
}
在 test.ts 中引用这个模块
import iam17 from '1am17'
这时会报错 找不到模块 “iam17” 或其相应的类型声明。这也不奇怪,毕竟我们还没有加类型声明,但是加在哪里呢? 我们先看下,如果不考虑 customConditions 配置,我们要如何给模块加类型声明呢?
- 加在 node_modules/@types 下面,一般是用单独的包,直接安装就行。但如果只是测试,直接增加文件 node_modules/@types/iam17/index.d.ts
- 写在模块中。
17 经过试验,只有在模块中增加一个名叫 foo.d.mts 的类型文件才行。想想也不难理解,其它的类型定义方式都是固定的,在不添加新规则的情况下,只有这种定义方式才是灵活的。
可能有的同学会有一个疑问,你怎么知道 "./foo.mjs" 的声明文件的名字叫 "foo.d.mts"?虽然可以去查文档,不过,17 告诉大家一个简单的办法:让 typescipt 自己生成 foo.mjs 的说明文件,看看叫什么就行了。同样的,如果不会写声明文件,也可以这样处理,这是学习如何写声明文件的一个方法。
customConditions 的默认条件
就算你没有在 tsconfig.json 中配置条件,ts 也会默认查找这两个条件 types,default,只要写在最前面就行。 比如
"exports": {
".": {
"types": "./foo.mjs",
"import": "./baz.mjs"
}
}
最后要注意的是,typescript 中的 customConditions 配置必须和 Node 的 --conditions 参数一起配合使用才行。
到这里文章就结束了,如果还有疑问,欢迎留言。完结,撒花~
转载自:https://juejin.cn/post/7370516186909589545