typescipt 配置精讲 | customConditions

发布于:2024-05-20 ⋅ 阅读:(102) ⋅ 点赞:(0)

大家好,我是 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 配置,我们要如何给模块加类型声明呢?

  1. 加在 node_modules/@types 下面,一般是用单独的包,直接安装就行。但如果只是测试,直接增加文件 node_modules/@types/iam17/index.d.ts
  2. 写在模块中。

17 经过试验,只有在模块中增加一个名叫 foo.d.mts 的类型文件才行。想想也不难理解,其它的类型定义方式都是固定的,在不添加新规则的情况下,只有这种定义方式才是灵活的。

可能有的同学会有一个疑问,你怎么知道 “./foo.mjs” 的声明文件的名字叫 “foo.d.mts”? 17 告诉大家一个简单的办法:让 typescipt 自己生成 foo.mjs 的说明文件,看看叫什么就行了。同样的,如果不会写声明文件,也可以这样处理,这是学习如何写声明文件的一个方法。

最后要注意的是,typescript 中的 customConditions 配置必须和 Node 的 --conditions 参数一起配合使用才行。

到这里文章就结束了,如果还有疑问,欢迎留言。完结,撒花~

番外

从去年最后一篇文章 Flutter IOS 新建打包发布全流程 2023 版 算起,已经有一年多没写文了。每次想动笔的时候,虽有千言万语,但又不知从何说起。17 在编程方面有自己的心得,最希望能把这些分享给大家,但这些内容并不是书本上写的。也可以说这些内容书上有写,但关键在于如何运用,这些很难通过教材的方式写出来,唯有实践。看似千变万化,实则万法归一。我说,我可以让开发效率提升三倍,估计没人信,也无法证明(证明的成本太高)。所以 17 决定还是先写一些绝对正确的,容易证明的内容。比如 const name = 'IAM17' name 不可改变,这就是绝对正确。后面如果 17 能有足够的威望,再考虑写那些不容易证明的内容。因为只有 17 有足够的威望,听到这些内容的人才可能会认真思考 17 说的他们认为不对的话。

17 很怀念那段写文的日子,每个周末都过得很充实。为了让后面的闲暇时间更有意义,后面 17 会努力多写一些文章,把 10 开发的经验都分享给小伙伴们,也希望小伙伴们多给些鼓励!