掌握 tsconfig.json
如果你使用VSCode
,通常每个项目根目录下都会有一个jsconfig.json
或tsconfig.json
文件,那这个文件的作用是什么呢?
按官方文档的解释来说,jsconfig.json
标记该目录是JS
项目根目录,并根据内部配置为项目内支持类型的文件提供语言服务(例如api
提示、导入路径提示等)
因为ts
文件相关配置无需在js
项目中配置,所以官方称jsconfig
属于tsconfig
的子集,后文中均以tsconfig
做说明
为什么需要
- 没有
tsconfig.json
时,VSCode
将每个文件都看作独立的单元。只要两个文件间没有通过模块导入语句显示的引用,这两个文件就没有公共的项目上下文 - 有
tsconfig.json
时,配置的属性会作用到项目内的每个文件,例如可以选择性的列出语言服务需要支持哪些文件或不支持哪些文件
简单来说就是有了tsconfig.json
文件后,设置的include
、exclude
等属性能够约束语言服务的作用范围。例如在a.js
中使用console.log(b)
时,因为文件上下文中没有b
,所以编辑器提供的语言服务会去查找有没有哪一个文件导出了b
,如果项目非常巨大的话,全目录查找效率会很低下,这时候就需要tsconfig.json
来指定哪部分文件才是需要查找的,从而提高编辑器效率
另外我们知道可以用typescript
库提供的tsc
命令编译输出js
文件,少量文件编译可以通过参数指定编译选项,但如果编译整个项目则需要利用tsconfig.json
来指定编译选项,同时统一编译策略也利于团队协作开发
tsc
命令行中指定的选项会始终覆盖tsconfig.json
中的对应配置
创建文件
tsconfig.json
文件可以手动创建,在vscode
中通过触发建议
快捷键即可提示相关属性
tsconfig.json
还可以通过tsc init
命令生成(需要先安装typescript
包),生成的内容只有compilerOptions
字段,并开启了几个常用属性,其他属性也通过注释做了详细的解释
tsconfig.json
文件可以是个空文件,只要创建了这个文件,所在目录就会被识别为项目根目录,相关属性会使用默认值
JS、TS 通用属性
include
指定允许被识别的文件或文件夹列表,运行使用通配符:
*
匹配 0 个或多个字符(不包括目录分隔符)?
匹配任意一个字符(不包括目录分隔符)**/
匹配任意一级或多级目录
如果路径某一部分只包含*
或.*
,那么这部分只会匹配支持的扩展名(.ts
、.tsx
、.d.ts
,如果设置了allowJs
则还包括.js
和.jsx
)
files
指定允许被识别的文件列表,如果找不到对应文件会报错
用于只有少量文件需要被识别时取代include
,files
与include
也可以同时存在。另外files
指定的文件不会被exclude
排除
exclude
指定不应该被识别的文件或文件夹列表,同样可以使用通配符
exclude
会默认排除node_modules
、bowser_components
、jspm_packages
和outDir
属性指定的目录
提示
未指定时,include
默认值为["**/*"]
;files
、exclude
默认为[]
extends
{
"extends": "./anotherConfig.json"
}
{
"extends": "./anotherConfig.json"
}
继承另一个配置文件中的配置,路径匹配规则采用NodeJS
匹配规则。主配置文件中的配置属性会覆盖extends
指定文件中的属性,对象中的不同属性会合并后作为完整的配置。多个配置文件不能通过extends
属性循环引用
需要注意files
、include
、exclude
字段不会发生合并,优先使用主配置文件中的配置
watchOptions
vueCompilerOptions
TS 相关属性
compilerOptions
compilerOptions
是TS
配置的主要部分
allowUnreachableCode
定义如何处理不会被访问到的代码,默认undefined
表示展示警告,还支持true
表示忽略,false
表示报错。例如:
function fn(n: number) {
if (n > 5) {
return true
} else {
return false
}
// 下面的代码永远不会被执行到
return true
}
function fn(n: number) {
if (n > 5) {
return true
} else {
return false
}
// 下面的代码永远不会被执行到
return true
}
allowUnusedLabels
定义如何处理未使用的标签,规则同allowUnreachableCode
。标签语法并不常用,若不了解可以参考MDN 文档
exactOptionalPropertyTypes
是否需要精确定义可选属性类型。默认TS
可选属性可以为undefined
,如果开启此选项则不会默认支持undefined
noFallthroughCasesInSwitch
是否需要switch
语句中每个非空case
都包含break
或return
noImplicitOverride
开启后子类重写父类方法必须添加override
关键字:
class Son extends Father {
override func() {}
}
class Son extends Father {
override func() {}
}
noImplicitReturns
启用后将严格检查函数是否有明确的返回值(默认的返回undefined
会报错)
noPropertyAccessFromIndexSignature
开启后将不能用点语法(obj.attr
)访问对象中通过索引定义的属性:
interface test {
a: string
[key: string]: string
}
let obj: test = { a: 'a' }
// 开启noPropertyAccessFromIndexSignature后将报错
// 属性“b”来自索引签名,因此必须使用[“b”]访问它。ts(4111)
console.log(obj.b)
interface test {
a: string
[key: string]: string
}
let obj: test = { a: 'a' }
// 开启noPropertyAccessFromIndexSignature后将报错
// 属性“b”来自索引签名,因此必须使用[“b”]访问它。ts(4111)
console.log(obj.b)
noUncheckedIndexedAccess
开启后
noUnusedLocals
开启后未使用的局部变量会报错
noUnusedParameters
开启后未使用的函数参数会报错
alwaysStrict
是否将每个文件都看作开启严格模式(use strict
),在ESModule
文件中会默认开启,具体规则可以参考MDN 文档
strictBindCallApply
开启后将检查call
、apply
、bind
中的参数类型是否与原函数定义的类型一致
strictFunctionTypes
开启后将使函数参数类型检查更加准确,例如一个更精确的函数类型不能赋值给类型的扩展集:
function fn(x: string) {
console.log('Hello, ' + x.toLowerCase())
}
type StringOrNumberFunc = (ns: string | number) => void
// Unsafe assignment is prevented
let func: StringOrNumberFunc = fn
function fn(x: string) {
console.log('Hello, ' + x.toLowerCase())
}
type StringOrNumberFunc = (ns: string | number) => void
// Unsafe assignment is prevented
let func: StringOrNumberFunc = fn
strictNullChecks
开启后null
和undefined
将看作具体的类型,而不会默认为其他类型的子类型
let a: string
// 默认null和undefined可以赋值给其他类型,开启strictNullChecks后将会报错
a = undefined
// 未开启strictNullChecks时b的类型别识别为string
// 开启后会识别为string|undefined
let a: string[] = []
let b = a.find((item) => item == 'a')
let a: string
// 默认null和undefined可以赋值给其他类型,开启strictNullChecks后将会报错
a = undefined
// 未开启strictNullChecks时b的类型别识别为string
// 开启后会识别为string|undefined
let a: string[] = []
let b = a.find((item) => item == 'a')
strictPropertyInitialization
开启后如果类中声明了类属性,但未在构造函数中设置该属性时会报错
noImplicitAny
是否允许不明确类型的变量存在。例如函数参数如果未指定类型,TS
会将类型看作any
,该属性定义是否允许这种默认的回退类型行为
noImplicitThis
开启后对this
类型无法识别时(隐式any
类型)会报错,例如:
class Name {
firstName: ''
lastName: ''
outputName() {
return function () {
// 这个函数中的this在调用时才能确定,而不是Name类,会报错
return this.firstName + this.lastName
}
}
}
class Name {
firstName: ''
lastName: ''
outputName() {
return function () {
// 这个函数中的this在调用时才能确定,而不是Name类,会报错
return this.firstName + this.lastName
}
}
}
useUnknownInCatchVariables
开启后catch
中的错误类型会由any
改为unknown
strict
开启严格模式,截至TS 4.3
开启strict
选项相当于开启了如下的八个编译选项:
- alwaysStrict
- strictBindCallApply
- strictFunctionTypes
- strictNullChecks
- strictPropertyInitialization
- noImplicitAny
- noImplicitThis
- useUnknownInCatchVariables
设置strict: true
后,这些选项也可以单独设置
allowUmdGlobalAccess
开启后允许以全局变量的形式访问UMD
模块导出
baseUrl
定义相对路径解析时相对的基准目录
默认为./
即相对于根目录,例如设置为src/
后,项目内的相对路径将从src
开始查找
module
定义项目使用的模块系统,支持CommonJS
, AMD
, System
, UMD
, ES6
, ES2015
, ES2020
, ESNext
, None
, ES2022
, Node16
, NodeNext
一般只需要设置为CommonJS
或ESNext
,这个属性决定了ts
文件编译后代码需要将模块化语句转换为何种模块化格式
moduleResolution
定义编译器查找模块导入文件的策略,支持Classic
或Node
。未指定时如果使用了module
为AMD
或System
或ES2015
时为Classic
,其他情况视为Node
Classic
策略是早期TS
默认的解析策略:相对导入时会依次查找相对目录下的.ts
、.d.ts
文件;非相对导入时会从当前目录依次遍历至根目录(baseUrl
)查找.ts
、.d.ts
文件
Node
策略是模仿NodeJS
的模块解析机制,不同的是TS
项目增加了扩展名的支持(.ts
、.tsx
、.d.ts
,如果设置了allowJs
则还包括.js
和.jsx
)
moduleSuffixes
用于在解析模块时添加默认后缀名进行搜索,例如:
"moduleSuffixes": [".ios", ".native", ""]
import * as foo from "./foo";
"moduleSuffixes": [".ios", ".native", ""]
import * as foo from "./foo";
此时会按照foo.ios.ts
、foo.native.ts
、foo.ts
的顺序进行搜索(此处省略了tsx
等扩展名替换步骤)