在 tsconfig.json 文件中,有一个配置项叫做 strict
,默认为 true,表示开启严格模式:
{
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
}
TypeScript 中的严格模式跟 JavaScript 中说的严格模式(即 use strict
)不是一个概念,它表示是否开启下面一系列的类型检查规则:
{
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true
}
意思是说:
- 如果你设置
strict
为 true 的话,那么上面所有的配置默认全是 true - 如果你设置
strict
为 false 的话,那么上面的所有配置默认全是 false - 你如果既设置了
strict
又单独设置了其中的部分配置,那么以单独设置的配置为准
知道了这层关系之后,接下来就逐个解释 strict
所关联的配置项分别代表什么含义:
noImplicitAny
不允许出现隐式的 any 类型。下图声明了一个判断奇偶的函数:
TypeScript 是可以进行自动类型推断的,nums 被推断成数字类型的数组,isOddNumber 被推断成返回布尔值的函数,但是参数 num 没有定义类型,TypeScript 只能推断为 any 类型,这就等价于写了下面的代码:
const nums: number[] = [1, 2, 3]
const isOddNumber = (num: any): boolean => (num % 2) !== 0
这样的代码是有 bug 的,例如:
isOddNumber('a') // true
isOddNumber(undefined) // true
建议开启 noImplicitAny 选项。
strictNullChecks
严格空检查。如果关闭此选项,则 null 和 undefined 两种类型是任意类型的子类型,即下面的语法不会报错:
let num: number = 1
let str: string = 'hello'
let student: { name: string; age: number } = { name: '小明', age: 12}
num = str = student = null
num = str = student = undefined
这样有可能引发未知的结果甚至 runtime error,因为下面的取值或运算都是合法的:
console.log(num + 10) // NaN
console.log(student.age) // TypeError: Cannot read property 'age' of undefined
建议开启 noImplicitAny 选项。
strictFunctionTypes
严格函数类型检查。我们知道,下面的赋值语法在 TypeScript 中是不允许的:
但可笑的是,在不开启 strictFunctionTypes 的情况下,如果你写出下面的代码,TypeScript 竟然是允许的:
function getCurrentYear(callback: (date: string | number) => void) {
callback(Math.random() > 0.5 ? '2020' : 2020)
}
getCurrentYear((date: string) => {
console.log(date.charAt(0))
})
真是毫无道理,所以强烈建议开启 strictFunctionTypes 选项。
strictBindCallApply
严格绑定检查。意思是在使用 bind、call 和 apply 语法的时候,是否进行参数检查,如果不开启的话,效果如下:
这明显是不合理的,因为如果通过 call 就能绕过了 TypeScript 的类型检查的话,代码中肯定会出现隐藏的 bug,所以强烈建议开启。
strictPropertyInitialization
严格属性初始化检查。这个选项要和 strictNullChecks 配合使用才行,否则会出现下面的报错:
该选项用于检查类的属性是否被初始化,如果开启则必须进行初始化,否则会出现下面的报错:
解决方法就是:
class User {
name: string = "";
setName(name: string) {
this.name = name;
}
}
建议开启 strictPropertyInitialization 选项。
noImplicitThis
不允许出现隐式any类型的this。JavaScript 是一门非常灵活的语言,TypeScript 对于 this 并不能很好地做类型推断,只能推断其为 any 类圆形了,例如像下面这种情况:
这种 any 类型的 this 在理解上是有歧义的,例如:
new Person('小明').say().call({name: '小红'})
// 小明
// hello, my name is 小红
建议开启 noImplicitThis 选项。
alwaysStrict
是否开启严格模式。这个不用多说,就是 JavaScript 中的 "use strict"
,肯定是要开启的。