如何给项目合理配置 tsconfig.json
- Published on
Table of Contents
最近在尝试使用 vue3+typescript+jsx 开发组件时,在配置 tsconfig.json 这一步出现了问题,编译报错、编译不通过,或是编译后的文件不符合预期等。之前写 ts demo 的时候,直接去网上 copy 一份配置就可以了,现在自己要开发项目,显然有些配置是行不通了。那么带着这些问题,我专门查阅了一些关于 typescript 项目基本配置的资料,并整理下来,防止同样的坑掉入两次。
以下示例基于 typescript@4.0.3 版本。
为什么要使用 tsconfig
TypeScript 使用 tsconfig.json 文件作为其配置文件,当一个目录中存在 tsconfig.json 文件,则认为该目录是 typescript 项目的根目录。
通常 tsconfig 主要包含两部分内容:指定待编译文件和定义编译选项。
实际上,我们不适用 tsconfig 配置文件,仅通过命令行也可以实现 ts 编译:
/*
--outFile // 编译后生成的文件名称
--target // 指定ECMAScript目标版本
--module // 指定生成哪个模块系统代码
index.ts // 源文件
*/
$ npx tsc --outFile index.js --target es5 --module commonjs index.ts
这段代码就可以实现注释中的功能,但是在实际项目开发中,往往是从整个项目入手,单一的命令行已经不能满足项目开发的需要了,这时就需要 tsconfig.json 配置文件来辅助我们进行代码编译。
接下来看下 tsconfig 的使用及注意事项。
初始化配置文件
安装 typescript 后,我们使用命令生成初始化配置文件:
$ npx tsc --init
这就会为我们自动创建一份较完整的 tsconfig.json 文件,其中的一些配置是通过注释的形式呈现,只需要我们在需要时修改一下配置项即可。生成的默认配置文件如下:
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}
虽然在项目目录下直接创建一个 tsconfig.json 文件也未尝不可,但通过命令行创建的配置文件附带了这么多的默认配置选项,还是太香了。
这时即可通过命令行编译 ts 文件了:
$ npx tsc index.ts
注意,tsc 的命令行选项具有更高的优先级,会覆盖 tsconfig.json 中的同名选项。
生成的配置项,到底哪些才是适配我们手头的项目呢?接下来我们来看一看。
解读常用的配置项
通过查阅 TypeScript Reference 文档,结合上述生成的配置项,我们可以总结出主要的两部分配置:
- 指定待编译文件:
exclude
,include
,files
- 定义编译选项:
compilerOptions
那么我们就来解读一下这些配置项,已经关键点。
指定待编译文件
官方列出的关于指定待编译文件的配置项其实不止这些,但在我们的项目中,这三项更为重要。这些配置可以帮助我们确保 typescript 选择正确的文件进行编译。
include
指定要包含在程序中的文件名或特定模式数组,这些文件名是基于 tsconfig.json 的相对地址。
{
"include": [
// "scr" // 会编译src目录下的所有文件,包括子目录
// "scr/*" // 只会编译scr一级目录下的文件
// "scr/*/*" // 只会编译scr二级目录下的文件
]
}
通常在指定一个目录后,这个目录下的所有 ts 文件都会被编译,即使没有被用到,如果是空文件等不符合要求的文件,或许还会报错。我之前在项目中会配置这个选项,现在由于一些没必要的报错,我更倾向于配置 files 选项。
exclude
指定在解析 include 时应跳过的文件名或特定模式数组。同样支持 glob 通配符。
注意这里的默认值是 ["node_modules", "bower_components", "jspm_packages"]
这些依赖包目录和 compilerOptions.outDir
指定的文件夹。大多数情况下,我们不需要额外配置 exclude 选项,因为这些默认值包含了大多数不需要编译的目录和文件,基本能满足需求。
跟 include 配置项一样,支持 glob 通配符:
*
匹配 0 或多个字符(不包括目录分隔符)?
匹配一个任意字符(不包括目录分隔符)**/
递归匹配任意子目录
files
指定需要编译的单个文件列表。通过 import 引入的其他模块的文件也会被编译。
如果是中小型项目,或不需要使用通配符匹配的项目,可通过这个配置来代替 include 配置项。目前我在封装组件的时候就是配置 files 指定编译程序的入口,然后通过模块关联编译其他文件。
其他的配置,如 extends, references, typeAcquisition 等一般很少用到,这里就不做过多解释,详情可查文档。
定义编译选项
编译选项 compilerOptions
有很多,通常分为以下几类:
- Basic Options
- Strict Type-Checking Options
- Additional Checks
- Module Resolution Options
- Source Map Options
- Experimental Options
- Advanced Options
compilerOptions
这就是定义编译选项,我们可以根据自己项目的需要,选择合适的配置项。由于配置项较多,这里就挑选几个常用易出错的点进行分析。
- target --- 编译后目标语言的版本,目前现代浏览器大多支持 ES6 特性,因此可以选择 ES2015 或更高版本。
- module --- 编译后代码的模块类型,可以根据不同的使用场景选择不同的模块化方案。
- lib --- 编译需要引入的库,因项目 javascript 版本和编译后使用场景而异,可以查阅各 ECMA 版本对应的库。
- allowJs --- 是否允许在你的 ts 文件中引入 js 模块,通常是允许的。
- checkJs --- 是否允许校验你的 js 代码并抛出错误,这个看实际情况而定吧。
- jsx --- 如果组件是使用 jsx 编写,这决定了输出的代码的组织形式,在 vue+jsx 要使用 preserve.
- declaration --- 是否生成 .d.ts 文件。
- outFile --- 所有代码输出到一个文件中,这通常是由 webpack/rollup 决定的。
- outDir --- 指定编译后文件的输出目录,如果是 npm 包通常配置 lib 文件夹。
- rootDir --- 指定文件最长公共路径,用于控制输出目录结构,通常是自动计算,也可以指定某些值。
- incremental --- 是否增量编译,可以提升再次编译速度。
- tsBuildInfoFile --- 增量编译文件存储位置。
- removeComments --- 移除注释,可以根据情况配置,或在 webpack/rollup 中集中处理。
- isolatedModules
- strict --- 开启严格类型检查。此项开启后 noImplicitAny, noImplicitThis, strictNullChecks, etc 会默认开启。
- noImplicitAny --- 不允许隐式 any 类型。
- noImplicitThis --- 不允许 this 是隐式 any 类型,谨慎使用。
- strictNullChecks --- 不允许把 null,undefined 赋值给其他类型的变量。
- strictFunctionTypes --- 不允许函数参数双向协变。
- strictBindCallApply --- 严格的 bind/call/apply 检查。
- strictPropertyInitialization --- 类的实例属性必须初始化。
- alwaysStrict --- 开启后,编译后的源代码都会注入
"use strict"
。 - noUnusedLocals --- 开启后,只声明未使用的变量会报错,默认关闭。
- noUnusedParameters --- 开启后,只声明未使用的函数参数会报错,默认关闭。
- noImplicitReturns --- 开启后,要求每个函数都要有返回值,默认关闭。
- noFallthroughCasesInSwitch --- 开启后,确保每个 switch...case 都必须有 break/return 语句,默认关闭。
- moduleResolution --- 指定模块解析策略。
- baseUrl --- 解析非相对模块的基地址,默认是当前目录。
- paths --- 路径映射,相对于 baseUrl.
- rootDirs --- 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化。
- esModuleInterop ---
主要的编译相关的配置已经差不多了,这些足以支撑你完成一个 typescript 项目,剩下还有不少配置没列在这,如果有需要还是查阅官方文档为主。
vue3+ts 项目中的配置
{
"compilerOptions": {
/* Basic Options */
"target": "es2015" /* 编译成 ES2015 */,
"module": "es2015" /* 编译后的代码模块化方案是 ES Module */,
"allowJs": true /* 允许 javascript 文件编译 */,
"jsx": "preserve" /* 组件使用 JSX 语法编写,这里采用 vue3 推荐的 preserve */,
"declaration": true /* 生成 .d.ts 文件,不过现在还没发现编译后声明文件的作用 */,
"outDir": "dist" /* 编译后的文件输出到 dist 文件夹 */,
/* Strict Type-Checking Options */
"strict": true /* 开启严格类型检查,其余的几项也会默认开启 */,
/* Module Resolution Options */
"moduleResolution": "node" /* 使用 nodejs 提供的模块解析策略 */,
"esModuleInterop": true /* 兼容 cjs 和 esm 模块化导入导出方案 */,
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"files": ["src/index.ts" /* 项目入口文件 */]
}
以上就是接下来使用 vue3+typescript+jsx 开发组件用例的 tsconfig.json 配置文件,目前仍在探索结合 rollup 的打包方案。