课程库 › TypeScript › TypeScript 起步 › 第 3 课
函数的类型 —— 参数、返回值、可选参数
普通课约 50 分钟
本课导读
上一课定了分寸:"边界即合同,合同要白纸黑字"——而代码里最重要的边界就是函数签名。本课把函数的类型写讲究:参数与返回值、"没有返回值"的 void、可选参数 ? 与默认值参数 = 的分工,最后认识箭头函数(现代 JS/TS 满地都是它)。学完后,你看任何函数的第一行就能读出它的完整合同。预计 50 分钟。
完整的函数签名
一行签名三层信息:收什么(两个 number)、吐什么(number)、连起来读就是这个函数的完整合同。上一课说返回值类型"通常可推断",那为什么还建议给正式函数写上?两个理由:
- 签名即文档:读代码的人(包括三个月后的你、包括 AI)看第一行就懂,不用钻进函数体
- 提前锁定意图:写了
: number,函数体里手滑return price + "元"会当场报错在函数内部——不写的话,错误类型会被推断出去,在几百行外的使用处才炸
void:说好了不交货
有些函数只干活不交货(打印日志、发通知)。"没有返回值"也是一种类型——void:
眼熟吗?Python 单元里"没写 return 的函数返回 None、接住 .sort() 的结果是 None"那类事故——TS 用 void 把它变成编译期问题:想把"不交货"当货用,代码跑都跑不起来。
可选参数 ? 与默认值参数 =
调用者不一定每个参数都想传。两种设计,分工不同:
怎么选?口诀:有合理兜底值 → 默认值参数(dept 不传就是总部,干脆利落);"没传"本身是个有意义的状态 → 可选参数(没指定渠道走站内信,逻辑分叉由你控制)。两条通用规矩:
- 可选/默认值参数都必须排在必填参数后面(
function f(a?: string, b: number)报错——和 Python 同款规矩,跨语言通用) - 可选参数在函数体内的类型是
string | undefined——竖线是什么?下下课"联合类型"正式登场,这里先脸熟
箭头函数:函数的简写形态
现代 JS/TS 代码里,你会大量遇到另一种函数写法——箭头函数:
三个认知就够用:
(参数) => 表达式是函数的简写;参数类型标注规则与普通函数一致- 注意
map里的(p) => p * 0.8没写 p 的类型却没报错——TS 从prices是number[]推断出 p 是 number(推断连回调参数都罩着,这叫上下文推断) map(整列加工)和filter(按条件筛选)——如果你学过 Python 的列表推导式,这就是 JS 世界的同一个思想;没学过也没关系,把它们当"数组的批量操作"即可
✍️ 练习
练习 1:补签名
给下面的函数补上完整的类型签名(参数 + 返回值),让三处调用都通过检查。
✅ 参考答案
function shippingFee(weight: number, express: boolean): number {
const base = weight * 5;
if (express) {
return base + 12;
}
return base;
}
console.log(shippingFee(2, false));
console.log(shippingFee(2, true));
起始代码的报错 TS7006(参数隐式 any)值得认识:strict 模式下 TS 拒绝"参数没类型"——这正是"边界必须白纸黑字"被写进了编译器规则。
练习 2:选对工具
设计函数 bookRoom:房间号必填(字符串);人数常见是 4 人;备注可有可无、有备注时要附在结果里。判断:人数和备注各该用"默认值参数"还是"可选参数"?实现并测试三种调用。
✅ 参考答案
function bookRoom(room: string, people: number = 4, note?: string): string {
let result = room + " 会议室," + people + " 人";
if (note !== undefined) {
result = result + "(" + note + ")";
}
return result;
}
console.log(bookRoom("A03"));
console.log(bookRoom("A03", 8));
console.log(bookRoom("A03", 8, "需要投影仪"));
选型复核:人数有合理兜底(4 人)→ 默认值;备注"没传"本身就是一种状态(不附加)→ 可选参数 + undefined 判断。
练习 3:箭头函数三连(挑战)
用 map / filter 和箭头函数完成三问:① 全部价格打八折 ② 筛出打折后仍超过 400 的 ③ (组合技)打折后仍超 400 的有几件?全程不写 for 循环。
✅ 参考答案
const prices = [599, 149, 1599, 459, 89];
const discounted = prices.map((p) => p * 0.8);
const stillPricey = discounted.filter((p) => p > 400);
const count = discounted.filter((p) => p > 400).length;
console.log(discounted);
console.log(stillPricey);
console.log("打折后仍超 400 的有 " + count + " 件");
链式组合 map(...).filter(...).length 是 JS/TS 数据处理的日常体态——而且注意:整条链上你没写一个类型,推断全程护航。
📝 随堂测验
1. function f(a: number): string 这行签名读出的“合同”是?
2. 返回类型 void 的函数,其返回值被拿去参与运算会怎样?
3. “人数不传就按 4 人”和“备注不传就不附加”,分别用什么?
4. prices.map((p) => p * 0.8) 里 p 没标类型却不报错,因为?
5. map 和 filter 的分工是?
本课小结
- 函数签名 = 完整合同:参数必写,正式函数返回值也写(签名即文档 + 错误锁定在函数内部)
void= 说好不交货;把"误用无返回值"变成编译期错误- 默认值参数(有兜底值)vs 可选参数 ?("没传"有意义);都排必填之后
- 箭头函数
(p) => 表达式:数组方法的标配;上下文推断连回调参数都罩着
下一课处理更立体的数据:对象怎么标类型?接口(interface)登场——给数据的"形状"签合同。
划选正文任意文字可高亮、批注或加入复习卡
讨论
载入中…