Oasis's Cloud

一个人的首要责任,就是要有雄心。雄心是一种高尚的激情,它可以采取多种合理的形式。
—— 《一个数学家的辩白》

TypeScript config 文件中的 extends


extends 的作用是继承另外的一个配置文件,对继承的配置文件进行合并或覆盖。例如:在一个项目中有多个页面,每个页面的 ts 配置文件希望做一些特殊的配置。可以采用上面的 extends 来实现。

在设计 extends 的时候,我们应该进行依赖反转的设计,将依赖关系放到每个页面维度处理,而不是放在公共的配置文件中进行处理。

举例说明:

一个功能包含 A、B 两个页面,A、B 希望在构建时让 tsc 处理自己实际依赖的文件,这里处理实际依赖的文件有一个前提条件,每个页面的结构较为稳定。

component
    A
    B
pages
    A
    B

pages/A 导入来 component/A,如何让 tsc 能只处理 pages/A 呢?

1.设置两个 tsconfig.json 文件,通过 include 来进行配置

设置多个 config 文件的方案维护起来比较麻烦,而且新增或删减都需要手工进行维护。但它也有一定的好处,可以应用灵活的配置。

在上述稳定结构的支撑下,是否可以将多个 config 文件的方案进行简化呢?

简化的含义是什么?这里的简化主要包含:从多个配置文件减少到一个或两个,从手动维护差异点改为自动化处理。最关键的点是差异管理。

好在 ts 提供了 extends 支持继承,这样可以将公共配置提取到 base config 中,同时借助 npm scripts 的能力,在 tsc 命令执行之前修改 tsconfig 文件为对应的项目配置文件。

例如提取如下公共配置

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "baseUrl": ".",
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "noImplicitAny": true,
    "removeComments": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "paths": {
      "@/*": ["../src/*"]
    }
  },
  "include": ["src"],
  "exclude": ["node_modules", "build", "public", "postcss.config.js"]
}

差异化配置:

{
  "extends": "./configs/tsconfig.base",
  "include": [
    "typings",
    "src/utils",
    "src/api/common",
    "src/components/common",
    "src/pages/${page}",
    "src/components/${page}"
  ]
}

其中 paths 的路径是相对于 base config 文件的。

在项目中会引入其他人或组织开发的库,而且有些库并未支持 ts,所以需要在项目中对这些库增加 d.ts 。增加的 d.ts 需要在 include 的范围内,否则在编译过程中会提示找不到类型。