课程库 › TypeScript › TypeScript 起步 › 第 1 课
为什么需要类型 —— 从一个 JS 运行时惨案讲起
普通课约 45 分钟
本课导读
欢迎来到 TypeScript。本单元假设你已经会任何一门语言的变量、函数和循环(JS 经验加分但不必须)——我们直接从"为什么"讲起:先亲眼目睹一场 JavaScript 的运行时惨案(代码没报错、结果悄悄错了),再看 TypeScript 如何把同一个事故拦在运行之前。看懂这场对比,你就理解了 TS 存在的全部理由。预计 45 分钟。
说明
本课程代码块的运行方式:点「▶ 运行」会先做完整的类型检查,检查通过才执行。有些示例的教学目标就是"让你看到报错"——这类代码块会用注释标注 // 预期报错:TSxxxx,红字出现即为"运行成功"。首次运行需加载 TS 编译器(几秒),之后流畅。
惨案现场:一个没有报错的 bug
电商结算页:单价 299,用户买 2 件,外加 15 元运费。数量从表单输入框读进来——而输入框给你的永远是字符串 "2"。下面用 any 类型模拟"JS 不设防"的世界(any 的含义课末揭晓):
运行看输出:应付金额 "299215"——没有报错、没有警告,程序"正常"跑完了。发生了什么:
- JS 是动态类型语言:变量装什么类型的值全看运行时,代码写错了它也照单全收
+遇到字符串就变"拼接":299 + "2"得"2992",再+ 15得"299215"- 最可怕的不是出错,是错得无声无息——这个数字会一路流到支付接口、订单记录、财务报表。等有人发现,可能已经是月底对账的时候
提示
类比记忆:动态类型像不核对币种的收银台——你递 200 日元,它当 200 美元收了,账面"完全正常"。事故不发生在收钱那一刻,而发生在月底盘点时——离案发现场越远,排查越贵。
同一个事故,TypeScript 的处理方式
TS 的解法:给函数的参数贴上类型标签,字符串根本进不了结算逻辑:
点运行——红字,代码根本没有执行:TS2345: Argument of type 'string' is not assignable to parameter of type 'number'(类型为 string 的实参不能赋给类型为 number 的形参)。读懂这次拦截:
price: number这种冒号语法是类型标注:给参数立门禁规矩——"只收数字"- 字符串
"2"想混进去,编译阶段(代码运行之前)当场按住——事故从"月底对账才发现"提前到"写代码的这一秒" - 修法也简单:把字符串转成数字再传,
checkout(299, Number(qtyFromForm))——练习 1 就是它
再看一个 JS 里更高频的惨案——拼写错误:
在 JS 里,order.pirce 静默返回 undefined,乘出个 NaN 一路传下去。TS 不但当场报错,还猜出了你的心思:Did you mean 'price'?(你是不是想写 price?)——类型系统认识你对象上的每一个属性。
类型到底是什么
用两句话把概念立正:
- 类型 = 值的"种类"标签:
299是 number、"2"是 string、true是 boolean。所有语言的值都有类型,区别只在谁来查、什么时候查 - TS 的核心动作 = 静态检查:代码还没运行,先把整个程序的类型账算一遍——"这里该是数字,你给了字符串"。像出发前的行前体检,而 JS 是"上了高速才发现刹车有问题"
TS 和 JS 的关系一句话说清:TypeScript = JavaScript + 类型说明书。TS 代码经过"编译"脱掉类型外衣变成纯 JS,浏览器最终跑的还是 JS——所以 TS 没有另起炉灶,你写的每一行 JS 知识都不作废,类型是加上去的安全层。
为什么此刻的你更需要它
类型系统最值钱的三个场景,恰好都在你的未来路线上:
- 项目变大:三百行以内 JS 随便写;三千行起,"这个函数到底接受什么参数"全靠记忆和祈祷——类型让代码自带答案
- 接手别人的代码:函数签名
checkout(price: number, qty: number): number本身就是最准的文档——不会过期、不会撒谎 - AI 时代(最重要):让 AI 写代码已是日常,但 AI 会一本正经地编造不存在的属性、传错类型的参数。类型检查是 AI 产出的自动验收员——幻觉代码在编译那一刻当场现形,而不是溜进生产环境。学 TS 不只是学一门语言,是给你的 AI 协作流程装质检closed环
- 最后揭晓
any:它是 TS 里"关掉类型检查"的后门——本课开头用它模拟 JS 世界。规矩从第一课立下:教学演示之外,不用 any(用了它,TS 的保护就对这段代码失效了)
✍️ 练习
练习 1:修复结算函数
把惨案现场修好:表单来的 qtyFromForm 转成数字再传给 checkout(提示:Number(字符串) 完成转换)。修好后应付金额应该是 613。
✅ 参考答案
function checkout(price: number, qty: number): number {
return price * qty + 15;
}
const qtyFromForm = "2";
const total = checkout(299, Number(qtyFromForm));
console.log("应付金额:" + total);
注意修法的含义:不是把类型标注删掉息事宁人,而是在边界处把数据洗成正确类型——"表单进来的都是字符串,入口处转换"从此是你的肌肉记忆。
练习 2:抓拼写小偷
下面代码有两处属性拼写错误(JS 里它们会静默产出 NaN 和 undefined)。先别运行,肉眼找;然后运行,看 TS 的报错是否和你找的一致,修复它们。
✅ 参考答案
const product = { name: "机械键盘", price: 599, stock: 12 };
console.log(product.name + " 库存 " + product.stock + " 件");
console.log("含税价 " + product.price * 1.06);
stcok 和 prise——TS 的报错里都带着 Did you mean 提示,等于抓贼还附赠画像。这类错误在纯 JS 项目里是排查耗时冠军。
练习 3:预言家挑战
三段代码,先预测各自的命运(通过运行 / 编译报错),再逐段取消注释验证。想想各自的理由。
✅ 参考答案
段一:报错(TS2363,算术运算的右侧必须是数字)。段二:通过!输出 "2992" string——TS 沿袭了 JS 的 + 拼接语义,这是它少数"放行危险动作"的地方(毕竟字符串拼接太常用),所以对 + 保持警惕这条 JS 时代的戒律在 TS 里依然有效。段三:报错(TS2345,两个参数类型都对不上位)。
三段的启示:TS 拦得住绝大多数类型事故,但不是全部——它是安全带,不是免死金牌。
📝 随堂测验
1. JS 里 299 + "2" + 15 得到 "299215" 且不报任何错,这类问题最大的危害是?
2. TypeScript 的“静态检查”指的是?
3. TypeScript 和 JavaScript 的关系是?
4. order.pirce(拼写错误)在 JS 和 TS 里的遭遇分别是?
5. 为什么说 AI 时代类型检查更重要了?
本课小结
- JS 动态类型的代价:错得无声无息("299215" 惨案、拼写返回 undefined)——事故离现场越远越贵
- TS 的答案:类型标注(
price: number)+ 静态检查——事故提前到编译时,还附赠 Did you mean - TS = JS + 类型说明书,编译后仍是 JS;
+拼接等少数语义仍需警惕——安全带不是免死金牌 - AI 时代的新理由:类型是 AI 生成代码的自动验收员
- 立规矩:教学演示之外不用 any(它是关掉保护的后门)
下一课正式盘点基础类型(string/number/boolean/数组),以及 TS 最贴心的设计——类型推断:能不写类型的地方就不写,让编译器替你干活。
划选正文任意文字可高亮、批注或加入复习卡
讨论
载入中…