typescript 模块解析真正策略之-- 一个ts类型报错引发的"惨案"

·  阅读 791

在引用公司的某个埋点包以后,发现vscode一直找不对它正确的类型定义,同样tsc编译的时候,也提示该包的定义文件上没有xx事件。于是开始排查

背景

首先项目node_modules结构如下:

image.png

本地代码 c.tsx

import log from 'B'
log.on()
复制代码

其中B(5.0)的index.d.ts定义如下所示

interface Sdk {
     on(type: string, hook: SdkHookListener): void;
}

复制代码

B(4.0)的index.d.ts定义如下所示,其中4.0里面是没有on函数的定义的

declare module 'log' {
    xxxx
}

复制代码

原因

去查找了typescript的相关文档,查看module resolution这一章。首先ts解析是有两个类型的: classic和node,由于配置的是node,所以看看node的策略。ts解析no-relative的包的策略是基于node的策略进行了相关拓展。

先看一下node的策略,详细可以看看这个链接,这里看一下重点

image.png

然后ts在node寻找策略的基础上,覆盖了extension,从index.js变为ts、tsx、d.ts。所以,当ts解析一个no-relative的包时,它的路径如下所示

image.png

但是即使按照上面的规则,在当前例子下,解析的应该也是B(5.0)的包,而不是B(4.0)的包,why? 4.0的版本有如此高的优先级?

然后,又翻烂了typescript的module这一章的文档,发现了关键词 Ambient Modules

image.png

image.png

这个定义和B(4.0)不是很像吗? 可能稍微有点区别就是使用的时候,ambient modules需要增加reference关键词。ok,再往下翻

image.png

也就是说,如果declare module的名称和包名一样的话,引用的时候就不用增加reference关键词。然后呢? 它的优先级是怎么回事?typescript官方文档翻烂了,也没有写。

就在快绝望时候,发现了这样一篇issue

image.png

根据上面的算法,官方已经告诉你了Ambient external Modules的优先级是最高的(完美符合B(4.0)包的定义),接下来才会按照module resolution的策略开始寻找。

解决

解决方案挺简单,在tsconfig.json增加一行这样配置

"compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "log": [
        "../node_modules/log"
      ]
    }
  },

复制代码
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改