函数类型基础
本教程共 80 篇 · 第 17 篇 · 更新于 2026-08-10 · 约 8 分钟阅读
本节目标:学会给函数参数和返回值加类型注解,理解 void 的用法,以及匿名函数如何自动推断类型。
TypeScript 对函数的类型检查主要集中在两个地方:参数的类型和返回值的类型。这两处写好之后,大多数由函数调用引发的 bug 就能在编译期被拦下。
参数类型注解
给参数加类型很简单,直接在参数名后面写 : 类型:
function greet(name: string) {
console.log("Hello, " + name);
}
greet("TypeScript"); // ✅
greet(42); // ❌ 类型 "number" 的参数不能赋给类型 "string" 的参数
在 TypeScript 7.0 中,strict: true 是默认值。这意味着如果你不给参数加类型,编译器会报错——因为 strict 开启了 noImplicitAny,不允许隐式的 any 类型。
// strict: true(7.0 默认)
function greet(name) {
// ~~~~ 参数 "name" 隐式具有 "any" 类型
console.log("Hello, " + name);
}
所以参数类型在 7.0 下基本上是必写的。这不是麻烦,是安全保障——相当于逼你把”这个参数是什么”想清楚。
返回值类型注解
返回值类型写在参数列表的圆括号后面:
function add(x: number, y: number): number {
return x + y;
}
const result = add(3, 5); // result 的类型是 number
实际上 TypeScript 很擅长推断返回值类型,你就算不写 : number,它也能自己推断出来。那为什么还要写呢?两个原因:
- 文档作用——一眼就知道这个函数返回什么。
- 防止无意篡改——如果你不小心改了函数逻辑导致返回值类型变了,编译器会立刻提醒你。
// 不写返回值类型,TS 推断为 number
function multiply(a: number, b: number) {
return a * b;
}
// 明确写出返回值类型
function divide(a: number, b: number): number {
return a / b;
}
Tip建议始终显式标注返回值类型,尤其是公开的 API 函数。这算是一种防御性编程——万一你后续改代码时不小心删掉了
return,编译器会替你发现。
void 返回
void 表示”这个函数不返回任何有意义的值”。
function logMessage(msg: string): void {
console.log(msg);
// 没有 return 语句
}
在 JavaScript 里,没有 return 的函数实际上会返回 undefined。但在 TypeScript 中,void 和 undefined 不是一回事。如果你显式写了 return 返回一个值,而函数签名标注了 void,编译器会报错:
function sayHello(): void {
return "hello"; // ❌ 类型 "string" 不能赋给类型 "void"
}
不过有个特殊规则需要知道:当你把一个有返回值的函数赋值给 void 类型的回调位置时,TypeScript 不会报错。这是有意为之的——否则 Array.forEach 就没法用了,因为 push 之类的方法会返回 number。
const src = [1, 2, 3];
const dst: number[] = [];
// forEach 要求回调返回 void,但 push 返回 number
// TypeScript 允许这样做
src.forEach((el) => dst.push(el));
这种设计让 TypeScript 保持了实用性——你不会因为一个 void 类型被卡住。
匿名函数与上下文类型推断
TypeScript 最聪明的一点是:当你把一个匿名函数传给一个已知类型的参数时,它会根据上下文自动推断匿名函数的参数类型。
const names = ["Alice", "Bob", "Charlie"];
// 你不需要给 name 加类型注解
names.forEach((name) => {
console.log(name.toUpperCase());
// ~~~~ name 被推断为 string
});
forEach 的回调类型是 (value: string, index: number, array: string[]) => void。TypeScript 知道 names 是 string[],所以自动推断 name 是 string。这就是”上下文类型推断”——参数的类型由函数所在的上下文决定,不需要你自己写。
再比如 map:
const lengths = names.map((name) => name.length);
// ~~~~ name: string
// lengths 的类型被推断为 number[]
你连返回值类型都没写,TypeScript 全帮你推出来了。这种推断在回调嵌套时特别省事——不用每层都写一遍类型。
Note上下文类型推断只对匿名函数有效。如果你把函数单独定义再传进去,参数类型就不会自动推断,需要你自己写注解。
// 单独定义的函数,参数需要显式标注类型
function getNameLength(name: string): number {
return name.length;
}
const lengths = names.map(getNameLength); // 没问题,因为 getNameLength 已经有类型
// 但如果定义时不写类型
function getNameLength2(name) {
// ~~~~ 隐式 any,strict 下报错
return name.length;
}
这个规则的核心是:匿名函数可以靠上下文推断,命名函数需要自己负责类型。两种方式各有用处——简单回调用匿名省事,复杂逻辑用命名函数更清晰。
小结
这一节涵盖了函数类型最基础的三个概念:参数类型、返回值类型、void。再加上上下文类型推断,你已经可以写出类型安全的函数了。下一节会深入函数参数的各种花样——可选参数、默认值、剩余参数和解构。