讲解

strict: true 是一组严格性开关的总开关,理解每个子开关才能在「报错太多」时做有依据的取舍(虽然推荐全开)。最重要的三个:strictNullChecks——null 和 undefined 不再能赋给任意类型,所有「可能为空」都必须显式处理,这是 TypeScript 价值的半壁江山,它消灭的是生产环境最高频的「Cannot read property of undefined」;noImplicitAny——推断不出类型时不许悄悄落成 any,倒逼你标注或修正;strictFunctionTypes——函数参数的检查从宽松的双变改为严格的逆变,堵住回调里的类型漏洞。

其余成员了解一下即可:strictBindCallApply 检查 bind/call/apply 的参数;strictPropertyInitialization 要求类字段在构造函数完成赋值(类章节见过);noImplicitThis 要求 this 有明确类型;useUnknownInCatchVariables 让 catch 的 e 默认是 unknown 而非 any;alwaysStrict 以严格模式解析并输出 "use strict"。

还有一个不在 strict 家族但强烈推荐的开关:noUncheckedIndexedAccess。它让数组下标和索引签名访问的返回类型自动附加 undefined(arr[0] 得到 T | undefined),逼你处理越界。代价是日常多写判空,团队可按代码风格决定;此外 noImplicitReturns(所有代码路径都有返回值)、noFallthroughCasesInSwitch(switch 穿透报错)也属于「低成本高回报」的附加开关。迁移老项目时可以先 strict: false 跑起来,再逐个打开——这是官方认可的渐进路径。

示例

strictNullChecks 下的空值处理范式(可选链、空值合并、提前返回):

interface Profile {
  nickname?: string;
  contact?: { email?: string };
}

function displayName(profile: Profile | null): string {
  if (profile === null) {
    return "访客";
  }
  const email = profile.contact?.email ?? "未填写邮箱";
  return `${profile.nickname ?? "匿名"}(${email})`;
}

console.log(displayName(null));
console.log(displayName({ nickname: "小林" }));
console.log(displayName({ contact: { email: "lin@example.com" } }));

catch 变量的 unknown 处理:

function parseSafe(raw: string): number | null {
  try {
    const n: number = JSON.parse(raw) as number;
    return typeof n === "number" ? n : null;
  } catch (e: unknown) {
    const message = e instanceof Error ? e.message : String(e);
    console.log(`解析失败:${message}`);
    return null;
  }
}

console.log(parseSafe("42"), parseSafe("oops"));

noUncheckedIndexedAccess 风格的下标防御(本教程全局未开该开关,示例用显式判空达到同等安全):

function firstChar(text: string): string | undefined {
  const ch: string | undefined = text.at(0);
  return ch;
}

const c = firstChar("TypeScript");
if (c !== undefined) {
  console.log(`首字母:${c.toLowerCase()}`);
}
console.log(firstChar("") === undefined ? "空串无首字母" : "有");

常见坑

  • 报错太多就关 strict:关掉 strictNullChecks 等于退化成「带补全的 JS」;迁移期逐项打开才是正路。
  • 用 ! 非空断言消红:value!.name 是「我保证不空」,保证错了运行时直接炸;优先 ?.、??、提前返回。
  • catch (e) 当 Error 用:useUnknownInCatchVariables 下 e 是 unknown,先 instanceof Error 再取 message。
  • 开关之间以为有依赖:strict 只是默认值来源,单独写 "strictNullChecks": false 可以覆盖——但请在代码评审里说清理由。

小结

strict 家族里 strictNullChecks、noImplicitAny、strictFunctionTypes 最关键;?. ?? 提前返回是空值三板斧;!.是逃生舱不是常规武器。下一章看异步代码的类型。