Agent X-Ray
RuntimeNotesAbout
Notes/代码工程/TypeScript 深度教程/第2章

第2章:语言基础 —— 变量、类型、运算与控制流

4 分钟 · 更新于 2026-09-01

第2章:语言基础 —— 变量、类型、运算与控制流

本章建立日常 TypeScript 代码的基础:变量声明、原始类型、数组与元组、对象、枚举、联合类型,以及 JavaScript 控制流怎样参与 TypeScript 的类型分析。


一、变量声明

现代代码优先使用 const,确实需要重新赋值时使用 let,避免 var 的函数作用域和提升行为。

ts
const appName = "Ticket Console";
let retryCount = 0;
retryCount += 1;

const 只阻止变量重新绑定,不会自动冻结对象:

ts
const config = { timeout: 3000 };
config.timeout = 5000; // 允许

需要只读约束时显式建模:

ts
const config: Readonly<{ timeout: number }> = { timeout: 3000 };

二、类型推断优先,必要时标注

ts
const language = "TypeScript"; // string
const version = 5;             // number
const strict = true;           // boolean

函数参数通常要标注,因为调用点不足以稳定推断契约:

ts
function multiply(left: number, right: number): number {
  return left * right;
}

不要给显而易见的局部变量重复标注:

ts
const count: number = 1; // 通常冗余

三、原始类型

常用类型包括:

  • string
  • number
  • boolean
  • bigint
  • symbol
  • null
  • undefined
ts
const route: string = "HKG-NRT";
const price: number = 1299.5;
const available: boolean = true;
const requestId: bigint = 9007199254740993n;
const token: symbol = Symbol("token");

不要使用包装对象类型 StringNumberBoolean 代替小写原始类型。

四、数组、只读数组与元组

ts
const prices: number[] = [1200, 1350, 1280];
const routes: Array<string> = ["HKG-NRT", "PVG-SIN"];

只读数组用于表达函数不会修改输入:

ts
function average(values: readonly number[]): number {
  return values.reduce((sum, value) => sum + value, 0) / values.length;
}

元组表达固定位置的不同含义:

ts
const coordinate: readonly [number, number] = [31.23, 121.47];
const result: [status: number, message: string] = [200, "OK"];

元组适合短小、位置语义明确的数据;字段较多时优先对象。

五、对象类型

ts
const user: {
  id: number;
  name: string;
  email?: string;
} = {
  id: 1,
  name: "Ada"
};

email?: string 表示属性可以不存在。开启 exactOptionalPropertyTypes 后,“属性缺失”与“显式写入 undefined”会被更严格地区分。

六、字面量类型与 as const

ts
let method = "GET";       // string
const fixedMethod = "GET"; // "GET"

对象属性默认仍可能被修改,因此通常会扩宽:

ts
const request = { method: "GET", path: "/users" };
// request.method 通常是 string

使用 as const 保留字面量并设为只读:

ts
const request = {
  method: "GET",
  path: "/users"
} as const;

七、联合类型

ts
let identifier: string | number;
identifier = "U-1001";
identifier = 1001;

使用联合类型前必须处理成员差异:

ts
function normalizeId(id: string | number): string {
  if (typeof id === "number") {
    return id.toString();
  }
  return id.trim();
}

这就是类型收窄:控制流让 TypeScript 在特定分支中获得更精确的类型。

八、nullundefined

严格模式下,不应默认把它们赋给其他类型:

ts
let selectedId: string | null = null;

可选链与空值合并:

ts
const city = user.profile?.address?.city ?? "未知城市";
  • ?.:左侧为 nullundefined 时停止访问。
  • ??:只在左侧为 nullundefined 时使用默认值。
  • ||:还会把 0""false 当作需要回退的值。

九、特殊类型

unknown

表示“值未知,使用前必须检查”:

ts
function printValue(value: unknown): void {
  if (typeof value === "string") {
    console.log(value.toUpperCase());
  }
}

any

关闭类型检查并具有传染性。只应作为迁移中的临时逃生口,并尽快缩小范围。

void

常用于表示函数返回值不会被调用者使用:

ts
function log(message: string): void {
  console.log(message);
}

never

表示不可能产生值,适合穷尽检查:

ts
function assertNever(value: never): never {
  throw new Error(`未处理的值:${String(value)}`);
}

十、枚举还是联合字面量

枚举会产生运行时代码:

ts
enum Status {
  Pending = "pending",
  Success = "success",
  Failed = "failed"
}

很多应用代码使用联合字面量更轻量:

ts
type Status = "pending" | "success" | "failed";

选择依据:

  • 需要运行时对象、反向引用或与既有 API 对齐时,可考虑枚举。
  • 只需类型约束和穷尽检查时,优先联合字面量或 as const 对象。

十一、运算与隐式转换

TypeScript 保留 JavaScript 的运行时规则:

ts
console.log("5" + 1); // "51"

类型系统能阻止一部分可疑组合,但不能改变 JavaScript。推荐:

  • 使用 ===!==
  • 明确转换:Number(text)String(value)
  • 金额避免浮点误差,按最小货币单位存整数。
  • 外部文本转换后检查 Number.isFinite

十二、控制流

ts
function describeScore(score: number): string {
  if (score >= 90) return "优秀";
  if (score >= 60) return "通过";
  return "未通过";
}

遍历数组优先 for...of

ts
for (const price of prices) {
  console.log(price);
}

for...in 遍历键名,不应把它误当成数组元素遍历。

switch 很适合判别联合:

ts
type State = "idle" | "loading" | "success" | "error";

function label(state: State): string {
  switch (state) {
    case "idle": return "等待";
    case "loading": return "加载中";
    case "success": return "成功";
    case "error": return "失败";
  }
}

十三、Symbol、Map 与 Set 的位置

symbol 可创建唯一键,但普通业务模型不应为了“高级”而滥用。键值数据优先评估 Map,去重集合使用 Set;它们将在第 5 章展开。

十四、常见误区

  1. 所有变量都显式写类型,制造噪声。
  2. 使用 String 而不是 string
  3. any 处理所有不确定数据。
  4. as 当数据转换或校验。
  5. 混淆 ||??
  6. 数组索引访问时假设元素必然存在。
  7. 使用元组承载过多字段,导致位置含义难读。
  8. 认为枚举是表达有限值集合的唯一方式。

十五、实践练习

  1. 定义 FlightStatus 联合类型并实现中文标签函数。
  2. 编写 average(readonly number[]),处理空数组。
  3. 将一组字符串价格安全转换为数字,过滤非法值。
  4. 比较 ||??0、空字符串、null 的结果。
  5. 用元组表示经纬度,再改成对象,比较可读性。

十六、总结

  1. const 优先,重新赋值时使用 let
  2. 让 TypeScript 推断局部类型,在公共边界明确契约。
  3. 联合类型配合控制流收窄,是 TypeScript 的核心表达方式。
  4. unknown 要求先验证,any 会关闭检查。
  5. null、数组索引和外部转换都要显式处理“不存在”。
  6. TypeScript 不改变 JavaScript 的运算和控制流语义。

请继续阅读:第3章:函数与对象。


原始资料引用


  • 第1章:开篇
  • 第3章:函数与对象

本章目录
一、变量声明二、类型推断优先,必要时标注三、原始类型四、数组、只读数组与元组五、对象类型六、字面量类型与 as const七、联合类型八、null 与 undefined九、特殊类型十、枚举还是联合字面量十一、运算与隐式转换十二、控制流十三、Symbol、Map 与 Set 的位置十四、常见误区十五、实践练习十六、总结原始资料引用Related Documents
苏ICP备2025204887号-2