Skip to content

前言

最近vscode总是类型检查报各种奇怪的错误,严重不符合预期。重新研究下这块的配置。想起什么写什么,这块场景比较多,别名叠加monorepo后更是难以理解,里面的坑特别多。

npx 执行方式

从当前目录向上一直查询node_module/.bin 查询命令。如果查询不到则下载命令到一个tmp。执行tmp中命令,执行后删除。

什么是tsc根目录

当tsc 不指定tsconfig.json 运行时,默认查找当前执行目录最近的tsconfig.json

  1. tsc运行时的目录 (不是)
  2. tsconfig.json 所在的目录 (正确)
  3. tsconfig.json中baseUrl 指的目录。(不是)

types 和 typeRoots

tsc启动时默认会查询项目根目录(项目根目录参考上面)以及祖先目录所有的node_modules/@types/* 目录中所有的软件包

typeRoots 指定查询的目录,当目录至少存在一个时才生效。否则会回退默认配置

types 指定@types中哪些目录会被加载。同上当目录至少存在一个时才会生效,否则回退。

rootDir 和 rootDirs

前者用于所有输入文件的最长路径,默认是自动计算的。 比如下面计算出路径是core/,当编译输出到outDir 会输出dist/a.js,会忽略前面core。如果想要保留core,把rootDir 修改成"./" 即可。

MyProj
├── tsconfig.json
├── core
│   ├── a.ts
│   ├── b.ts
│   ├── sub
│   │   ├── c.ts
├── types.d.ts

rootDirs 用于虚拟目录,可以将两个在不同目录中文件,视为在一个目录。比如下a.ts 可以使用import b from "./b"

json
rootDirs: ["./core1", "./core2"]
MyProj
├── tsconfig.json
├── core1
│   ├── a.ts
├── core2
│   ├── b.ts
├── types.d.ts

tsc如何加载软件包

tsc中import 语句

模块解析

如果tsconfig中moduleResolution: Node 时,按照node的模块查找规则。查找规则按照path+place 的方式

path是相对或者绝对路径时,直接按照路径解析。相对路径不包含 'xx/xxx' path是动态路径时,比如** import xx from 'xx' **。从当前文件开始查找同级目录是否存在node_modules/xx。

place规则如下

  • xx.ts
  • xx 中存在package.json 而且存在package.types所指的文件或者exports.types指定的文件
  • @types/xx
  • xx/index.ts

同时针对文件扩展名,按照.ts .tsx .d.ts 顺序解析。

另外还可以通过修改设置baseUrl和paths 映射来修改这种行为。默认情况下只要设置了baseUrl,paths会默认添加 { "": ["./"] } 配置

如果想追踪每个module的解析情况,可以使用traceResolution: true 打印解析日志 tsc编译时会从入口文件开始,将相关的依赖文件同时编译。如果配置了noResolve选项指定了某些模块不编译,编译会报错。

从变量引用和类型引用两个角度分析。
变量角度

ts
// test.ts
import { a } from "a"  // 1. 寻找是否能根据baseUrl和paths匹配到模块 2.依次向上查询node_modules/a是否存在 3.如果是文件夹,先检查package.json描述,如果package.json 不存在,检查index.ts 是否存在。
import b from "a/b" // 1. 同上 2. 检查node_modules/a/b 是否存在。 3. 同上3
import c from './c' // 1. 检查是否配置了rootDirs。 2. ./c是否是文件夹,如果是参考1.3 
import d from 'd.xx' // 1. 同上1

类型角度

ts
// test.ts
import { a } from "a"  // 1. 寻找是否能根据baseUrl和paths匹配到模块,a.ts存在,直接导出a.ts的命名空间,如果只有a.js存在,需要查找a.d.ts,如果a.d.ts未查找到,同时allowJS: false,在查询是否存在当前module的 declararion 声明,查找终止。
                       // 2. 向上查找node_modules/a.d.ts,如果是文件夹,先查找package.json相关定义,再查找node_modules/a/index.d.ts。再加载同级@types/a 文件夹,按照上述步骤处理。 
import b from "a/b" // 1. 同上1 2.
import c from './c' // 1. 同上述文件夹处理方式 2. 检查是否有declaration 声明
import d from './d.xx' // 后缀当做文件名处理

vscode中typescript

npm i -D typescript后。会安装typescript/core、tsc和tsserver。其中tsserver负责对vscode工作区文件的检查

declare

  1. 当一个d.ts 不存在export 或者import 会被视为全局文件。通过declare定义都是全局的,否则就是局部的。
  2. namespace 理解成同一个文件中的模块化。里面的定义需要通过export 导出。否则也是局部的。

vscode检查ts 结论

  1. 每次点开一个ts文件时,tsserver会使用这个文件最近tsconfig.json 文件,如果这个配置文件包含这个文件。则使用这个文件的规则。
  2. 如果这个tsconfig.json 不包含这个文件,比如被排除或者不在include范围内。就会使用项目根目录的tsconfig.json
  3. 如果项目根目录的tsconfig.json 也不包含这个文件。则会使用tsserver 默认的规则检查。

vscode检查js

如果开启allowjs会按照上面检查ts的流程检查,如果没有会按照先查询tsconfig.json ,再查询jsconfig.json 逻辑。

引用资料