TypeScript 循环:从基础到实战的完整指南
在编写程序时,重复执行某些操作是再常见不过的需求。比如你要处理一个用户列表,给每位用户发送欢迎消息;或者遍历一个数据数组,计算总和。这种“重复执行”的逻辑,就是编程中的“循环”。而 TypeScript 作为 JavaScript 的超集,提供了强大且类型安全的循环机制。今天我们就来深入聊聊 TypeScript 循环,帮助你从零开始掌握它。
TypeScript 循环不仅让你的代码更简洁,还能提升可读性和安全性。尤其当你结合类型系统使用时,循环中的变量错误会被编译时发现,避免运行时崩溃。接下来,我会用实际案例带你一步步掌握这些技巧。
常见的循环结构:for、while、do-while
TypeScript 支持三种基本的循环语法:for、while 和 do-while。它们在功能上各有侧重,但核心思想都是“重复执行一段代码”。
for 循环:最常用的计数循环
for 循环是处理已知次数循环的首选。它的结构清晰,适合遍历数组、执行固定次数的操作。
// 示例:打印 1 到 5 的数字
for (let i = 1; i <= 5; i++) {
console.log(`当前数字是:${i}`);
}
代码注释:
let i = 1:定义循环变量 i,初始值为 1,代表当前循环次数。i <= 5:循环继续的条件,只要 i 小于等于 5,就继续执行。i++:每次循环结束后,i 自增 1。console.log:输出当前值,用于观察执行过程。
这个结构就像一条自动运行的传送带:从 1 开始,每走一步就加 1,直到达到 5 就停下来。
while 循环:条件驱动的循环
while 循环更适合“不知道要循环多少次”的场景。只要条件为真,就一直执行。
// 示例:猜数字游戏(用户输入数字,直到猜对为止)
let secretNumber = 42;
let guess: number;
while (guess !== secretNumber) {
guess = prompt("请输入一个数字:") as unknown as number;
if (guess !== secretNumber) {
console.log("猜错了,再试一次!");
}
}
console.log("恭喜你,猜对了!");
代码注释:
let guess: number:声明一个变量,用于存储用户输入。注意这里用unknown as number是为了处理prompt返回的字符串类型,实际开发中应做更安全的类型校验。while (guess !== secretNumber):只要 guess 不等于 secretNumber,就继续循环。prompt是浏览器内置函数,返回字符串,需强制类型转换。- 一旦猜对,跳出循环,输出成功信息。
注意:while 循环容易出现“死循环”——如果条件永远为真,程序将无限运行。因此一定要确保条件最终能变为 false。
do-while 循环:至少执行一次的循环
do-while 的特点是:先执行,再判断。也就是说,即使条件一开始为假,循环体也会执行一次。
// 示例:用户登录验证(至少尝试一次)
let username: string;
let password: string;
do {
username = prompt("请输入用户名:") || "";
password = prompt("请输入密码:") || "";
if (username !== "admin" || password !== "123456") {
console.log("用户名或密码错误,请重试。");
}
} while (username !== "admin" || password !== "123456");
console.log("登录成功!");
代码注释:
do { ... } while (...):先执行一次登录输入,再判断是否成功。- 即使用户第一次输入就错,也会提示错误,然后重新输入。
- 适合需要“至少执行一次”的交互逻辑,比如表单验证。
💡 小贴士:
do-while常用于命令行程序、登录流程、游戏主循环等场景。
遍历数组:for...of 与 forEach
在处理数据集合时,for...of 是 TypeScript 中最优雅的遍历方式。它专为可迭代对象设计,语法简洁,类型安全。
for...of:推荐用于数组和集合
// 示例:遍历用户数组并输出信息
const users: string[] = ["Alice", "Bob", "Charlie"];
for (const user of users) {
console.log(`欢迎用户:${user}`);
}
代码注释:
const user of users:每次循环取出 users 数组中的一个元素,赋值给 user。const保证变量不可变,避免意外修改。- 类型推断自动识别 user 为
string类型,无需手动声明。
forEach:函数式编程风格的遍历
forEach 是数组的方法,适合执行副作用操作(如打印、发送请求)。
// 示例:使用 forEach 遍历并处理数据
const scores: number[] = [85, 92, 78, 96];
scores.forEach((score, index) => {
console.log(`第 ${index + 1} 位同学的成绩是:${score}`);
});
代码注释:
score:当前元素的值。index:当前元素的索引(从 0 开始)。=>是箭头函数,语法简洁,适合短函数。- 适合不需要返回值的遍历操作。
⚠️ 注意:
forEach不能用break或continue跳出循环。如果需要提前退出,应使用for...of或for循环。
循环中的类型安全:TypeScript 的优势
TypeScript 的最大优势之一是类型检查。在循环中,类型信息能帮你避免很多低级错误。
// 示例:类型安全的循环处理对象数组
interface Product {
id: number;
name: string;
price: number;
}
const products: Product[] = [
{ id: 1, name: "笔记本电脑", price: 5999 },
{ id: 2, name: "鼠标", price: 99 },
{ id: 3, name: "键盘", price: 299 }
];
// 正确使用类型推断
for (const product of products) {
// TypeScript 自动识别 product 为 Product 类型
console.log(`产品:${product.name},价格:${product.price} 元`);
// 如果误写 product.prce,编译时就会报错!
// error: Property 'prce' does not exist on type 'Product'
}
关键点:
Product是一个接口,定义了对象结构。products: Product[]声明了数组类型。for (const product of products)中,product的类型被自动推断为Product。- 一旦写错字段名(如
prce),TypeScript 会在编译阶段报错,防止运行时崩溃。
实战案例:处理用户订单数据
让我们用一个完整的实战案例来巩固所学。假设你有一个订单系统,需要计算所有订单的总金额,并筛选出高价订单。
// 订单数据模型
interface Order {
id: number;
items: { name: string; price: number }[];
status: "pending" | "shipped" | "delivered";
}
// 模拟订单数据
const orders: Order[] = [
{
id: 1001,
items: [{ name: "T恤", price: 89 }, { name: "牛仔裤", price: 299 }],
status: "shipped"
},
{
id: 1002,
items: [{ name: "耳机", price: 199 }],
status: "pending"
},
{
id: 1003,
items: [{ name: "手机壳", price: 39 }, { name: "充电宝", price: 159 }],
status: "delivered"
}
];
// 计算所有订单的总金额
let totalAmount = 0;
for (const order of orders) {
// 遍历每个订单的 items
for (const item of order.items) {
totalAmount += item.price;
}
}
console.log(`所有订单的总金额为:${totalAmount} 元`);
// 筛选出金额超过 200 的订单
console.log("\n高价订单列表:");
for (const order of orders) {
const orderTotal = order.items.reduce((sum, item) => sum + item.price, 0);
if (orderTotal > 200) {
console.log(`订单 ${order.id},总价:${orderTotal} 元`);
}
}
代码注释:
Order接口定义了订单结构,包括 id、items 数组、status。reduce是数组方法,用于累加 items 的价格。- 外层循环遍历所有订单,内层循环处理每个订单的项目。
orderTotal > 200用于筛选高价订单。- 输出清晰,逻辑分明,适合实际项目使用。
循环中的最佳实践与常见陷阱
✅ 推荐做法
- 优先使用
for...of遍历数组,语法简洁。 - 避免在循环中频繁调用
push或splice,可能影响性能。 - 使用
const声明循环变量,避免意外修改。 - 利用 TypeScript 的类型系统,减少运行时错误。
❌ 常见错误
- 死循环:忘记更新循环变量,如
for (let i = 0; i < 10; )忘记i++。 - 类型错误:在
forEach中误用变量类型,编译器无法发现。 - 性能问题:在大数组中使用
for循环时,避免在循环体内做耗时操作。
结语
TypeScript 循环是构建复杂逻辑的基础工具。无论是简单的计数、条件判断,还是处理复杂数据结构,掌握这些循环机制,都能让你的代码更高效、更安全。
从 for 到 for...of,从 while 到 forEach,每一种循环都有其适用场景。关键在于理解它们的本质,并在实际项目中灵活运用。
记住,编程不是记住语法,而是学会用合适的工具解决合适的问题。当你能熟练运用 TypeScript 循环,你就离写出高质量代码又近了一步。