不定期更新,遇到一个,查了一个,明白一个就记录下。

tsconfig.json,一个TS的配置文件,通常在项目根目录下,决定该项目,TS应该怎么去编译等等。

配置项

compilerOptions

编译选项相关的东西。

module

JS的模块系统和JS本身语言是分开的2块。这个配置项指定了TS将你的代码用指定的模块系统编译出来,常见的如 AMDdefine() ,还有 CommonJsES6 的模块系统也就是 importexport

moduleResolution

模块系统如何解析,当我们导入一个模块时,按照何种模块系统解析,建议按照 node 。如果module配置项已经配置了,则会有个默认值 "AMD" or "System" ? "Classic" : "Node"

baseUrl

查找非相对模块( ../../modules/jquery/index )时,告诉TS去哪里查找。配置的路径值如果是相对的,是相对于 tsconfig.json 所在路径为基准路径的。
假设配置的路径是 ./ ,我们想要引入 app/some/index.js 时,因为app和 tsconfig.json 是同一目录级别,所以输入 app\ 可以获得TS的文件路径提示( some 会在选择列表中)。

  1. // 简单的目录结构如下
  2. - app
  3. - some
  4. - index.js
  5. - configs
  6. - tsconfig.json

paths

这个配置是相对于 baseUrl 来的,用来对一些模块做映射,跟 webpack 里的 alias 同样的意思。这个配置项如果有,则必须有 baseUrl

假设文件路径如下:

  1. - src
  2. - utils
  3. - foo.js
  4. - tsconfig.json

希望这么引入:

  1. import foo from '@utils/foo'
  1. // tsconfig.json
  2. // 这里如果用的是create-react-app,baseUrl的值做了限制,只允许src|node_modules
  3. // 这里设为src
  4. {
  5. "complierOptions": {
  6. baseUrl: 'src',
  7. paths: {
  8. "@*": ['*']
  9. }
  10. }
  11. }

这里的 @* 中的就是匹配所有,就是个正则的那个**。匹配 @ 开头的模块字符,获取到 @ 后所有的内容,然后配合 baseUrl 的值,去 src 下寻找。通过TS编译后,示例这里编译的值就是 utils/foo

但是这个路径是个绝对路径,通常项目如果是 webpack 编译的话,这里是无法识别出来正确模块路径的,需要告诉 webpack 如何去解析 utils/foo ,所以需要配置 webpackresolve 字段。

  1. // webpack.config.js
  2. {
  3. resolve: {
  4. alias: {
  5. '@utils': path.resolve(__dirname, '../src/utils/')
  6. }
  7. }
  8. }

这样,TS和webpack都知道如何去查找模块了。

这里如果是用paths依赖的方法去设置,ts无法给与@下的路径提示,只有拼写出@utils后,才能获取@utils目录下的提示。我通常不会再去配置paths,直接利用ts的baseUrl,可以获取到完整提示,结合下面的npm包,让webpack可以正确识别。

另外,手写webpack的alias也比较麻烦,有些成熟的npm包,帮助解决这个事,将TS paths 同步到 webpack的alias中。如 tsconfig-paths-webpack-plugin

esModuleInterop

大多数的npm中的模块,都是 commonjs 风格,这里回顾下 commonjs 的模块对外导出我们一般都是

  1. module.exports = {
  2. hello: function(){}
  3. }
  4. // 或者
  5. exports.hello = function(){}
  6. // 第三方的模块比如react,可以看到是这么做得
  7. module.exports = react
  8. module.exports = reactDom

没有ES6的默认导出功能,所以如果要引入commonjs的模块所有的接口,我们需要 import * as mod from './mod.js 但是这种写法属于 es6 写法,mod此时是作为一个空间对象(即这种导入是将所有暴露的接口都扔到一个名为mod的对象上,对象本身不能作为函数调用)不能直接以 mod() 来使用。

所以为了能让我们这样使用 import mod from ./mod.js , TS中这个配置项打开后做了2件事。
第一件事,也会顺带开启 allowSyntheticDefaultImports ,该配置项允许我们从没有默认导出接口的模块中,按照有默认导出的形式来导入模块,也就是不会检查,不会报错提醒我们模块没有默认导出。
第二件事,也就是 esModuleInterop 本身,会使用2个辅助函数,一个是 __importDefault,一个是__importStar。

  1. var __importDefault = (this && this.__importDefault) || function (mod) {
  2. return (mod && mod.__esModule) ? mod : { "default": mod };
  3. };
  4. // 支持默认导入,当模块是esm时,不管是AMD还是CMD模块系统,先加载过来,然后判断加载过来的对象身上是否有esmodule,如果有,则直接使用模块。
  5. 如果没有的话,则给模块本身包装成{default: mod},有一个默认的属性,意为默认导出。
  1. var __importStar = (this && this.__importStar) || function (mod) {
  2. if (mod && mod.__esModule) return mod;
  3. var result = {};
  4. if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
  5. result["default"] = mod;
  6. return result;
  7. };
  8. // 支持星号导入形式,将模块所具有的的属性(自身的),全部放到模块本身,再加一个default来实现模块具备默认导出,default本身就是mod