TypeScript函数重载 #
一、函数重载基础 #
1.1 什么是函数重载 #
函数重载允许一个函数根据不同的参数类型或数量,有不同的行为和返回类型。
typescript
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any): any {
return a + b;
}
const num = add(1, 2);
const str = add('hello', 'world');
1.2 重载签名和实现签名 #
typescript
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any): any {
return a + b;
}
- 前两行是重载签名(overload signatures)
- 最后一行是实现签名(implementation signature)
二、基本重载 #
2.1 不同参数类型 #
typescript
function format(value: number): string;
function format(value: string): string;
function format(value: number | string): string {
if (typeof value === 'number') {
return value.toFixed(2);
}
return value.toUpperCase();
}
console.log(format(3.14159));
console.log(format('hello'));
2.2 不同参数数量 #
typescript
function makeDate(timestamp: number): Date;
function makeDate(year: number, month: number, day: number): Date;
function makeDate(yearOrTimestamp: number, month?: number, day?: number): Date {
if (month !== undefined && day !== undefined) {
return new Date(yearOrTimestamp, month - 1, day);
}
return new Date(yearOrTimestamp);
}
const d1 = makeDate(1234567890);
const d2 = makeDate(2024, 1, 1);
2.3 不同返回类型 #
typescript
function parse(value: string): string;
function parse(value: string, radix: number): number;
function parse(value: string, radix?: number): string | number {
if (radix !== undefined) {
return parseInt(value, radix);
}
return value;
}
const str = parse('123');
const num = parse('123', 10);
三、重载规则 #
3.1 实现签名必须兼容所有重载 #
typescript
function fn(x: string): string;
function fn(x: number): number;
function fn(x: boolean): boolean;
function fn(x: string | number | boolean): string | number | boolean {
return x;
}
3.2 重载签名不能有实现 #
typescript
function add(a: number, b: number): number {
return a + b;
}
function add(a: string, b: string): string {
return a + b;
}
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any): any {
return a + b;
}
3.3 调用时只使用重载签名 #
typescript
function fn(x: string): string;
function fn(x: number): number;
function fn(x: string | number): string | number {
return x;
}
fn('hello').toUpperCase();
fn(123).toFixed(2);
fn(true);
四、实际应用 #
4.1 DOM操作 #
typescript
function createElement(tag: 'a'): HTMLAnchorElement;
function createElement(tag: 'canvas'): HTMLCanvasElement;
function createElement(tag: 'table'): HTMLTableElement;
function createElement(tag: string): HTMLElement {
return document.createElement(tag);
}
const anchor = createElement('a');
const canvas = createElement('canvas');
const table = createElement('table');
const div = createElement('div');
4.2 事件处理 #
typescript
function on(element: HTMLElement, event: 'click', handler: (e: MouseEvent) => void): void;
function on(element: HTMLElement, event: 'keydown', handler: (e: KeyboardEvent) => void): void;
function on(element: HTMLElement, event: string, handler: (e: Event) => void): void {
element.addEventListener(event, handler);
}
on(document.body, 'click', e => {
console.log(e.clientX);
});
on(document.body, 'keydown', e => {
console.log(e.key);
});
4.3 API请求 #
typescript
interface User {
id: number;
name: string;
}
function fetchUser(): User[];
function fetchUser(id: number): User;
function fetchUser(id?: number): User | User[] {
if (id === undefined) {
return [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
}
return { id, name: 'User' };
}
const users = fetchUser();
const user = fetchUser(1);
4.4 工具函数 #
typescript
function get(obj: object, key: string): any;
function get<T>(obj: T, key: keyof T): T[keyof T];
function get(obj: any, key: string): any {
return obj[key];
}
const user = { name: 'Alice', age: 25 };
const name = get(user, 'name');
const age = get(user, 'age');
五、重载与联合类型 #
5.1 何时使用重载 #
typescript
function len(s: string): number;
function len(arr: any[]): number;
function len(x: any): number {
return x.length;
}
function len(x: string | any[]): number {
return x.length;
}
5.2 重载的优势 #
typescript
function createElement(tag: 'a'): HTMLAnchorElement;
function createElement(tag: 'canvas'): HTMLCanvasElement;
function createElement(tag: string): HTMLElement;
function createElement(tag: string): HTMLElement {
return document.createElement(tag);
}
5.3 选择建议 #
| 场景 | 推荐 |
|---|---|
| 返回类型不同 | 函数重载 |
| 参数类型不同且返回类型不同 | 函数重载 |
| 参数类型不同但返回类型相同 | 联合类型 |
| 需要精确的类型推断 | 函数重载 |
六、高级重载 #
6.1 泛型重载 #
typescript
function identity<T>(arg: T): T;
function identity<T extends string>(arg: T): T;
function identity<T>(arg: T): T {
return arg;
}
const str = identity('hello');
const num = identity(123);
6.2 条件返回类型 #
typescript
function process<T extends string | number>(
value: T
): T extends string ? string : number {
if (typeof value === 'string') {
return value.toUpperCase() as any;
}
return value * 2 as any;
}
const str = process('hello');
const num = process(5);
6.3 构造函数重载 #
typescript
interface Animal {
name: string;
}
interface AnimalConstructor {
new (name: string): Animal;
(name: string): Animal;
}
function createAnimal(ctor: AnimalConstructor, name: string): Animal {
return new ctor(name);
}
七、常见错误 #
7.1 实现签名过于宽泛 #
typescript
function fn(x: string): string;
function fn(x: number): number;
function fn(x: any): any {
return x;
}
fn(true);
7.2 重载顺序错误 #
typescript
function fn(x: any): any;
function fn(x: string): string;
function fn(x: number): number;
function fn(x: any): any {
return x;
}
function fn(x: string): string;
function fn(x: number): number;
function fn(x: any): any {
return x;
}
7.3 可选参数处理 #
typescript
function fn(x: number): number;
function fn(x: number, y: number): number;
function fn(x: number, y?: number): number {
return y !== undefined ? x + y : x;
}
八、实用示例 #
8.1 类型安全的Object.keys #
typescript
function keys<T extends object>(obj: T): (keyof T)[];
function keys(obj: object): string[];
function keys(obj: object): string[] {
return Object.keys(obj);
}
const user = { name: 'Alice', age: 25 };
const userKeys = keys(user);
8.2 类型安全的assign #
typescript
function assign<T, U>(target: T, source: U): T & U;
function assign<T, U, V>(target: T, source1: U, source2: V): T & U & V;
function assign(target: any, ...sources: any[]): any {
return Object.assign(target, ...sources);
}
const result = assign({ a: 1 }, { b: 2 });
const result2 = assign({ a: 1 }, { b: 2 }, { c: 3 });
8.3 类型安全的querySelector #
typescript
function querySelector(selector: 'div'): HTMLDivElement;
function querySelector(selector: 'a'): HTMLAnchorElement;
function querySelector(selector: string): HTMLElement | null;
function querySelector(selector: string): HTMLElement | null {
return document.querySelector(selector);
}
const div = querySelector('div');
const anchor = querySelector('a');
const span = querySelector('span');
九、总结 #
本章介绍了TypeScript函数重载:
重载要点 #
- 重载签名定义函数的多种调用方式
- 实现签名必须兼容所有重载
- 调用时只使用重载签名
- 重载顺序很重要
使用场景 #
- 不同参数类型返回不同类型
- 不同参数数量返回不同类型
- 需要精确的类型推断
- API设计提供更好的类型提示
最佳实践 #
- 重载签名从具体到宽泛排序
- 实现签名处理所有情况
- 优先考虑联合类型
- 避免过于复杂的重载
最后更新:2026-03-26