tsconfig 中 strict 模式有什么作用?
简化版
strict 是 TypeScript 的严格类型检查总开关,开启后会启用一组更严格的规则,比如 strictNullChecks、noImplicitAny、strictFunctionTypes 等。它能提前发现更多潜在错误,但迁移老项目时可能需要逐步开启。
详细版
常见严格选项:
noImplicitAny:不允许隐式 any。strictNullChecks:null/undefined不再随便赋给其他类型。strictFunctionTypes:更严格检查函数参数兼容。strictPropertyInitialization:类属性必须初始化。
strictNullChecks 很重要:
function f(name?: string) {
// name.toUpperCase(); // 可能 undefined
return name?.toUpperCase();
}
严格模式能让空值、隐式 any、未初始化属性等问题在编译期暴露。
完整版教学
一、strict 不是单个规则
strict: true 会打开一组规则。随着 TS 版本演进,strict 包含的检查可能增加,因此它代表更强的类型安全姿态。
新项目建议直接开启。老项目如果历史 any 很多,可以分阶段治理。
二、noImplicitAny 防止类型黑洞
如果参数没有类型,TS 推不出来时会给 any。隐式 any 很危险,因为它会绕过后续检查。
function add(a, b) {
return a + b;
}
开启 noImplicitAny 后,必须显式声明或让 TS 能推断。
三、strictNullChecks 提升空值安全
不开启时,null 和 undefined 可以赋给很多类型,容易运行时报错。开启后,你必须明确处理空值。
这会让代码多一些判断,但线上空指针问题会少很多。
四、迁移策略
老项目可以先开启部分规则,比如 noImplicitAny,再处理 strictNullChecks。也可以对边界层使用 unknown 和类型守卫,逐步收窄。
不要为了通过编译到处写 as any,那相当于把问题藏起来。
五、面试追问与工程落地
strict 常见追问是“老项目能不能直接全开”。现实中不一定。全开可能一下暴露几千个错误,阻塞业务迭代。更合理的是分模块、分选项逐步开启,新增代码严格,老代码逐步偿还类型债。
还会问 strict 是否会影响运行时性能。TypeScript 类型检查发生在编译期,类型本身会被擦除,严格模式不会让运行时代码变慢。它影响的是开发阶段的检查力度和迁移成本。
工程里要警惕用 as any、// @ts-ignore 快速压错。短期能过编译,长期会把类型系统打穿。更好的做法是补准确类型、收窄 unknown、封装边界适配层。
六、按风险分层迁移,而不是机械消除报错
strict 是一组严格家族选项的总开关,并允许单独关闭某个子项。TypeScript 后续版本可能把新的检查纳入 strict,因此升级编译器后出现新错误并不等于运行时代码突然变化,而是静态分析覆盖面扩大。迁移前应固定编译器版本并记录错误基线。
{
"compilerOptions": {
"strict": true,
"useUnknownInCatchVariables": true,
"noUncheckedIndexedAccess": true
}
}
后两个选项适合严格工程,但要注意 noUncheckedIndexedAccess 并不是 strict 家族自动开启的选项。假设老项目有 1000 个类型错误,可以先按边界输入、空值、函数兼容、类初始化四类统计,再以模块为单位把错误数从 1000 降到 700、300、0;不要用 1000 个 as any 把仪表盘瞬间清零。
| 选项 | 主要防护 | 常见迁移代价 |
|---|---|---|
noImplicitAny | 隐式类型黑洞 | 补参数和第三方声明 |
strictNullChecks | 空值误用 | 补联合类型与分支判断 |
strictFunctionTypes | 不安全参数兼容 | 调整回调签名;方法语法有例外 |
strictPropertyInitialization | 类字段未初始化 | 构造器赋值或明确初始化策略 |
strictFunctionTypes 主要更严格地检查函数语法的参数位置,方法语法为兼容常见层级结构保留了较宽松行为。面试中把它简单说成“所有函数参数都完全逆变”会遗漏这个现实边界。
严格迁移的目标是恢复真实类型关系,而不是让错误计数归零;所有 suppress 注释都应有原因、范围和清理计划。
七、常见误区与追问
- 误区:strict 只是 strictNullChecks 的别名。 它会开启一组严格家族选项,空值检查只是其中一项。
- 误区:开启 strict 会让生产 JavaScript 运行更慢。 类型检查主要发生在编译期,类型会被擦除;成本集中在开发、检查和迁移阶段。
- 误区:strict 会自动开启所有名字里带严格含义的选项。
noUncheckedIndexedAccess等增强选项不属于 strict 家族,需要单独配置。 - 追问:为什么升级 TypeScript 后 strict 项目会新增错误? 新版本可能扩展 strict 的检查行为或改进控制流分析,应结合发布说明评估。
- 追问:老项目应该先开哪个选项? 没有唯一顺序,通常先做错误基线和边界隔离,再选择收益高且改动可控的规则分模块推进。
- 追问:strictFunctionTypes 检查所有方法吗? 它对函数语法更严格,但方法声明存在兼容性例外,不能用一个结论覆盖全部写法。
- 追问:可以用 skipLibCheck 解决业务错误吗? 它主要跳过声明文件内部检查,不会修复业务源码类型关系,也不应替代依赖版本治理。
八、加强记忆
strict 模式是 TS 的“安全带”。它会让你写代码时麻烦一点,但能把很多空值、隐式 any、未初始化问题提前暴露出来。
迁移时把报错当成风险清单逐类消化,而不是用断言抹掉,strict 才真正形成工程收益。