第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");
不要使用包装对象类型 String、Number、Boolean 代替小写原始类型。
四、数组、只读数组与元组
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 在特定分支中获得更精确的类型。
八、null 与 undefined
严格模式下,不应默认把它们赋给其他类型:
ts
let selectedId: string | null = null;
可选链与空值合并:
ts
const city = user.profile?.address?.city ?? "未知城市";
- ?.:左侧为 null 或 undefined 时停止访问。
- ??:只在左侧为 null 或 undefined 时使用默认值。
- ||:还会把 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 章展开。
十四、常见误区
- 所有变量都显式写类型,制造噪声。
- 使用 String 而不是 string。
- 用 any 处理所有不确定数据。
- 把 as 当数据转换或校验。
- 混淆 || 与 ??。
- 数组索引访问时假设元素必然存在。
- 使用元组承载过多字段,导致位置含义难读。
- 认为枚举是表达有限值集合的唯一方式。
十五、实践练习
- 定义 FlightStatus 联合类型并实现中文标签函数。
- 编写 average(readonly number[]),处理空数组。
- 将一组字符串价格安全转换为数字,过滤非法值。
- 比较 || 与 ?? 对 0、空字符串、null 的结果。
- 用元组表示经纬度,再改成对象,比较可读性。
十六、总结
- const 优先,重新赋值时使用 let。
- 让 TypeScript 推断局部类型,在公共边界明确契约。
- 联合类型配合控制流收窄,是 TypeScript 的核心表达方式。
- unknown 要求先验证,any 会关闭检查。
- null、数组索引和外部转换都要显式处理“不存在”。
- TypeScript 不改变 JavaScript 的运算和控制流语义。
请继续阅读:第3章:函数与对象。
原始资料引用