不定期更新,遇到一个,查了一个,明白一个就记录下。
tsconfig.json,一个TS的配置文件,通常在项目根目录下,决定该项目,TS应该怎么去编译等等。
配置项
compilerOptions
编译选项相关的东西。
module
JS的模块系统和JS本身语言是分开的2块。这个配置项指定了TS将你的代码用指定的模块系统编译出来,常见的如 AMD
的 define()
,还有 CommonJs
, ES6
的模块系统也就是 import
和 export
。
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
会在选择列表中)。
// 简单的目录结构如下
- app
- some
- index.js
- configs
- tsconfig.json
paths
这个配置是相对于 baseUrl 来的,用来对一些模块做映射,跟 webpack 里的 alias 同样的意思。这个配置项如果有,则必须有 baseUrl
假设文件路径如下:
- src
- utils
- foo.js
- tsconfig.json
希望这么引入:
import foo from '@utils/foo'
// tsconfig.json
// 这里如果用的是create-react-app,baseUrl的值做了限制,只允许src|node_modules
// 这里设为src
{
"complierOptions": {
baseUrl: 'src',
paths: {
"@*": ['*']
}
}
}
这里的 @*
中的就是匹配所有,就是个正则的那个**。匹配 @ 开头的模块字符,获取到 @ 后所有的内容,然后配合 baseUrl 的值,去 src 下寻找。通过TS编译后,示例这里编译的值就是 utils/foo
。
但是这个路径是个绝对路径,通常项目如果是 webpack 编译的话,这里是无法识别出来正确模块路径的,需要告诉 webpack 如何去解析 utils/foo
,所以需要配置 webpack 的 resolve
字段。
// webpack.config.js
{
resolve: {
alias: {
'@utils': path.resolve(__dirname, '../src/utils/')
}
}
}
这样,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
的模块对外导出我们一般都是
module.exports = {
hello: function(){}
}
// 或者
exports.hello = function(){}
// 第三方的模块比如react,可以看到是这么做得
module.exports = react
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。
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
// 支持默认导入,当模块是esm时,不管是AMD还是CMD模块系统,先加载过来,然后判断加载过来的对象身上是否有esmodule,如果有,则直接使用模块。
如果没有的话,则给模块本身包装成{default: mod},有一个默认的属性,意为默认导出。
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
// 支持星号导入形式,将模块所具有的的属性(自身的),全部放到模块本身,再加一个default来实现模块具备默认导出,default本身就是mod