函数重载
核心定义
函数重载(Function Overloading)是静态类型语言中的一项重要特性,允许同一函数名有多个参数和返回值类型组合。
在TypeScript中,函数重载通过类型系统在编译时完成匹配,而不是像某些语言那样在运行时决定调用哪个函数。
关键特点
| 特性 | 说明 | 实际意义 |
|---|---|---|
| 同名函数 | 所有重载的函数名称相同 | 统一API入口,降低使用复杂度 |
| 参数差异 | 通过参数类型或数量来区分不同版本 | 编译器根据调用参数自动匹配 |
| 返回值不同 | 不同重载可以返回不同类型的结果 | 精确的类型推断,IDE智能提示 |
| 静态匹配 | 在编译时确定调用哪个重载版本 | 零运行时开销 |
TIP
重载(Overload)指同一作用域内多个同名函数声明,通过参数列表区分。在TypeScript中,这种重载是"声明式"的,最终只有一个实现函数。
三大核心原则
输入参数输出类型映射
TypeScriptfunction reverse(input: string): string; function reverse<T>(input: T[]): T[];1
2参数组合模式匹配
TypeScriptfunction createElement(tag: 'img'): HTMLImageElement; function createElement(tag: 'input'): HTMLInputElement;1
2类型安全保证
TypeScriptfunction padLeft(value: string, padding: number): string; function padLeft(value: string, padding: string): string; // 实现需校验padding类型1
2
3
语法实现
标准实现
函数重载在TypeScript中的实现分为三个关键部分:
TypeScript
// 1. 重载签名声明(类型契约)
function transformData(input: string): string[];
function transformData(input: number): string;
// 2. 实现签名(具体逻辑)
function transformData(input: any): any {
// 3. 实现体
if (typeof input === "string") {
return input.split("");
}
return input.toString().split("").join("-");
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
各部分功能说明:
- 重载签名(Overload Signatures):
- 定义函数的不同调用方式
- 只包含类型信息,不包含实现
- 可以有多个重载签名
- 示例中定义了对
string和number参数的不同处理
- 实现签名(Implementation Signature):
- 包含实际的函数实现
- 参数类型必须兼容所有重载签名
- 返回值类型通常比重载签名更宽泛
- 实现体(Implementation Body):
- 包含实际业务逻辑
- 需要处理所有重载签名定义的情况
- 通常使用类型判断
typeof/instanceof来区分不同情况
关键规范
重载签名必须前置声明:
- 重载签名必须在实现签名之前声明
- 编译器按顺序匹配重载签名
- 错误示例:
TypeScript// ❌ 错误:实现签名在前 function transformData(input: any): any { ... } function transformData(input: string): string[];1
2
3实现签名参数需兼容所有重载类型:
- 实现签名的参数类型必须涵盖所有重载签名的参数类型
- 常用解决方案:
- 使用联合类型:
string|number - 使用
any类型(不推荐) - 使用
unknown类型(推荐)
- 使用联合类型:
- 推荐实现:
TypeScript// 联合类型 function transformData(input: string | number): string[] | string { // 实现 } // 推荐实现:使用unknown类型 function transformData(input: unknown): unknown { // 实现 }1
2
3
4
5
6
7
8
9返回值类型在实现层可放宽:
- 实现签名的返回值类型可以比重载签名更宽泛
- 可以使用
联合类型、any或unknown类型 - 但建议尽可能精确
- 示例:
TypeScript// 重载签名 function getLength(obj: string): number; function getLength(obj: any[]): number; // 实现签名 function getLength(obj: string | any[]): number { return obj.length; }1
2
3
4
5
6
7
8
最佳实践
参数类型处理
TypeScript// 推荐:使用类型保护 if (typeof input === "string") { // 处理string逻辑 } else if (typeof input === "number") { // 处理number逻辑 }1
2
3
4
5
6返回值类型处理
TypeScript// 推荐:明确返回值类型 function transformData(input: string | number): string[] | string { if (typeof input === "string") { return input.split(""); // string[] } return input.toString(); // string }1
2
3
4
5
6
7错误处理
TypeScript// 处理未覆盖的类型 function transformData(input: string | number): string[] | string { if (typeof input === "string") return input.split(""); if (typeof input === "number") return input.toString(); throw new Error("Unsupported parameter type"); }1
2
3
4
5
6
高级用法示例
可选参数重载
TypeScriptfunction createElement(tag: string): HTMLElement; function createElement(tag: string, props: object): HTMLElement; function createElement(tag: string, props?: object): HTMLElement { // 实现 }1
2
3
4
5
6不同类型返回
TypeScriptfunction parseInput(input: string): string[]; function parseInput(input: number): number[]; function parseInput(input: string | number): string[] | number[] { if (typeof input === "string") return input.split(""); return [input, input]; }1
2
3
4
5
6
7复杂类型推断
TypeScriptinterface User { name: string; age: number; } function getUser(id: string): Promise<User>; function getUser(id: number): User; function getUser(id: string | number): User | Promise<User> { if (typeof id === "string") return fetchUser(id); return findUser(id); }1
2
3
4
5
6
7
8
9
10
11
12
TIP
在实际项目中,建议将复杂重载逻辑拆分为多个函数,保持代码可读性。对于简单场景,优先考虑使用联合类型而非重载。
函数重载与联合类型的区别
函数重载和联合类型都可以用于处理多种类型的输入,但它们有不同的使用场景和特点:
| 特性 | 函数重载 | 联合类型 |
|---|---|---|
| 类型推断 | 精确到每个重载版本 | 只能推断为联合类型 |
| 代码复杂度 | 声明多个重载签名,代码量较大 | 单一签名,代码简洁 |
| 灵活性 | 可以为不同输入指定不同返回类型 | 所有输入共享相同的返回类型 |
| 可读性 | 重载签名清晰展示所有支持的参数组合 | 联合类型需要在实现中处理所有情况 |
| 适用场景 | 不同参数类型需要不同返回类型 | 不同参数类型但返回类型相同 |
示例对比
TypeScript
// 使用函数重载
function process(value: string): string;
function process(value: number): number;
function process(value: string | number): string | number {
if (typeof value === 'string') {
return value.toUpperCase();
} else {
return value * 2;
}
}
// 使用联合类型
function processUnion(value: string | number): string | number {
if (typeof value === 'string') {
return value.toUpperCase();
} else {
return value * 2;
}
}
// 使用效果
const result1 = process("hello"); // 类型为 string
const result2 = process(123); // 类型为 number
const result3 = processUnion("hello"); // 类型为 string | number
const result4 = processUnion(123); // 类型为 string | number1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

