你将理解严格模式实际启用了什么,并知道如何处理它在既有项目中揭示出的典型错误。
在 Kodokon 中打开本课"strict": true 并不是单个选项,而是一个启用整整一族检查的聚合项:strictNullChecks、noImplicitAny、strictFunctionTypes、strictBindCallApply、strictPropertyInitialization、noImplicitThis、useUnknownInCatchVariables 以及 alwaysStrict。每个新的 TypeScript 版本都可能再增加更多:启用 strict 就等于订阅了未来的检查。每个标志仍可被单独关闭,这使得在既有代码库上进行渐进式迁移成为可能。
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
}
}影响力最大的两个标志是 strictNullChecks 和 noImplicitAny。前者从所有类型中移除 null 和 undefined:任何可能缺失的值都必须被声明为 T | undefined 并在使用前处理。后者则拒绝让未标注的参数退回到 any。二者结合,消除了 JavaScript 两大类 bug:“cannot read property of undefined”以及未经检查的值的扩散。useUnknownInCatchVariables 补全了这幅图景:catch 中的变量是 unknown,因为 JavaScript 允许你抛出任何东西。
function findPort(
env: Record<string, string | undefined>
): number {
const raw = env["PORT"];
if (raw === undefined) {
return 3000;
}
return Number.parseInt(raw, 10);
}
declare function riskyOperation(): void;
try {
riskyOperation();
} catch (err) {
const message =
err instanceof Error ? err.message : String(err);
console.error(message);
}常见的迁移错误及其真正的解法。“Object is possibly undefined”:优先使用收窄(if)、可选链 ?. 或 ?? 默认值,而不是非空断言 !,后者只是把崩溃转移到别处。“Property has no initializer”(strictPropertyInitialization):在构造函数中初始化,而不是在字段上动用 !。还要当心 ?? 与 || 的陷阱:port || 3000 会连 0 和 "" 也一并替换掉,而 port ?? 3000 只替换 null 和 undefined。
interface Settings { retries?: number }
function resolveRetries(s: Settings): number {
const bad = s.retries || 3;
const good = s.retries ?? 3;
return good;
}
const names = ["Ada", "Linus"];
const first = names[0];
const upper = first?.toUpperCase() ?? "N/A";在聚合项之外,有三个选项值得团队讨论。noUncheckedIndexedAccess 会给每一次索引访问(arr[i]、dict[key])都加上 undefined:更安全,但在数组操作代码中会显得冗长——许多团队只在新项目上采用它。exactOptionalPropertyTypes 区分“属性缺失”与“属性被设为 undefined”,对补丁至关重要。skipLibCheck 会跳过对依赖项 .d.ts 文件的检查:这是在构建时间与检测库之间冲突之间的一个刻意取舍。
"strict": true 在 tsconfig.json 中究竟做了什么?retries?: number 被设为 0 时,retries || 3 与 retries ?? 3 有什么区别?// @ts-expect-error 而非 // @ts-ignore?