CLASS 01 · 2026-02-04 · 基础

静态检查

静态类型是软件安全的第一道防线。本讲以冰雹数列为引例,引入类型、静态检查的概念,并阐述 6.102 对好软件的三大品质追求:免于错误、易于理解、便于修改。

从冰雹数列说起

我们将用一个贯穿本课的例子——冰雹数列(Hailstone sequence)——来理解静态检查的价值。规则如下:从正整数 \(n\) 开始,若 \(n\) 为偶数则下一项是 \(n/2\),若 \(n\) 为奇数则下一项是 \(3n+1\),直到数列到达 1 为止。

例如从 \(n=10\) 开始:\(10 \to 5 \to 16 \to 8 \to 4 \to 2 \to 1\),长度为 7。

什么是类型

类型(type)是一组值以及可在这些值上执行的运算的集合。

例如,number 是 TypeScript 中表示数字的类型,支持加减乘除等运算;string 是字符串类型,支持拼接、切片等运算。类型告诉我们一个表达式「能是什么、能做什么」。

静态类型语言

TypeScript 是一门静态类型(statically-typed)语言。变量可以在编译时被赋予类型,由此编译器能推导出使用这些变量的表达式的类型。

// 显式类型注解:在变量名后写 :type
let n: number = 10;
let name: string = "hailstone";

// 类型不匹配会立即被编译器发现
n = "oops"; // Error: Type 'string' is not assignable to type 'number'.

三种检查方式

编程语言发现错误的能力可以分为三个层次:

静态检查是最理想的情形——错误在萌芽阶段、尚未造成任何运行时损失时就被捕获。

function hailstoneLength(n: number): number {
  let length = 1;
  while (n !== 1) {
    if (n % 2 === 0) {
      n = n / 2;
    } else {
      n = 3 * n + 1;
    }
    length = length + 1;
  }
  return length;
}

// 静态检查:下面这行在编译阶段就会报错
console.log(hailstoneLength("ten"));
//               ^^^^^^^^^^^^^^^ Argument of type 'string' is not assignable to parameter of type 'number'.

数组与函数

TypeScript 的数组是另一种类型,写法是 Array<T>T[],表示「元素类型为 T 的可变长序列」。

let primes: number[] = [2, 3, 5, 7, 11];
let empty: string[] = []; // 空数组也是合法的

把一段逻辑封装成可复用的模块时,我们编写函数并附上规格注释:

/**
 * 计算冰雹数列的长度。
 * @param n 起始正整数 (n > 0)
 * @returns 从 n 到达 1 所需的步数(含首尾)
 */
function hailstoneLength(n: number): number { /* ... */ }

修改值 vs. 重新赋值

这是两个常被混淆的概念:

let a: number = 5;
a = 10;          // 重新赋值:a 现在指向 10

let arr: number[] = [1, 2, 3];
arr[0] = 99;     // 修改:数组对象本身被改变了

把假设写下来

为一个变量写下类型,就是在文档化你对它的假设。类型注解既是给编译器的指令,也是给未来读者(包括未来的你自己)的承诺:「这个变量始终是一个 number」。

黑客式编程 vs. 工程

软件工程不是「先跑起来再说」。工程师是悲观主义者:他们假设自己会犯错、假设需求会变化、假设后来者会误读代码,于是用静态类型、规格说明、测试等工具在错误造成损失之前就将其捕获。

6.102 的目标:好软件的三大品质

这三大品质贯穿整个课程,也是我们做每一个工程取舍时的坐标系。

核心要点

静态检查在编译时自动发现类型错误,优于运行时才发现或静默出错。

类型是一组值及其运算的集合;静态类型语言让编译器替你守住类型约定。

三大品质免于错误、易于理解、便于修改——这是 6.102 所有技术决策的出发点。