1. TypeScript函数重载基础入门第一次接触TypeScript函数重载这个概念时我完全被它绕晕了。明明是同个函数名却能处理不同类型的参数这简直像变魔术一样。后来在实际项目中踩过几次坑才明白函数重载其实是TypeScript给我们的一个强大工具它能让我们写出更清晰、更安全的代码。简单来说函数重载就是让一个函数能够根据传入参数的不同类型不同或数量不同执行不同的逻辑并返回不同类型的结果。举个例子我们有个处理用户输入的函数当传入字符串时要做A处理传入数字时要做B处理。如果没有函数重载我们可能得写一堆类型判断代码会变得很臃肿。而有了函数重载TypeScript编译器就能在编译阶段帮我们检查类型是否正确大大减少运行时错误。这里有个特别容易混淆的点函数重载只是类型声明层面的重载实际执行时还是同一个函数体。也就是说我们最终还是要在一个函数实现里处理所有可能的参数组合。这点和某些其他语言比如Java的函数重载不太一样需要特别注意。2. 函数重载的两种写法详解2.1 声明与实现分离的写法这种写法是我最常用的也是官方文档推荐的方式。它的结构非常清晰先写几个只有类型声明的重载签名最后再写具体的函数实现。// 重载签名1处理单个字符串 function formatInput(input: string): string; // 重载签名2处理数字数组 function formatInput(input: number[]): string; // 实际实现 function formatInput(input: any): string { if (typeof input string) { return Text: ${input.toUpperCase()}; } else if (Array.isArray(input)) { return Numbers: ${input.join(, )}; } throw new Error(Invalid input type); }我在实际项目中发现几个关键点重载签名只包含参数和返回类型没有函数体实现函数的参数类型要能覆盖所有重载签名的情况这里用了any但更好的做法是用联合类型实现函数的返回类型也要兼容所有重载签名2.2 函数表达式写法这种写法更适合在需要把函数赋值给变量或作为参数传递的场景。它的特点是把所有重载签名都写在类型注解里。const formatInput: { (input: string): string; (input: number[]): string; } (input: any) { if (typeof input string) { return Text: ${input.toUpperCase()}; } else if (Array.isArray(input)) { return Numbers: ${input.join(, )}; } throw new Error(Invalid input type); };这种写法有个小坑要注意箭头函数的参数类型必须足够宽泛以覆盖所有重载签名。我刚开始经常在这里卡住明明重载签名写对了但实现部分总是报类型错误。3. 实际应用场景分析3.1 表单验证场景在表单处理中函数重载特别有用。比如我们要处理用户注册信息可能有以下几种情况// 情况1邮箱注册 function register(email: string, password: string): User; // 情况2第三方登录 function register(provider: google | facebook, token: string): User; // 实际实现 function register( arg1: string, arg2: string ): User { if (arg2.length 30) { // 假设token通常比较长 return thirdPartyRegister(arg1 as google | facebook, arg2); } else { return emailRegister(arg1, arg2); } }这个例子展示了如何根据参数特征这里用token长度作为判断依据来决定调用哪个逻辑。虽然看起来有点取巧但在实际业务中这种模式很常见。3.2 API请求封装另一个典型场景是封装HTTP请求。我们可能要根据不同参数返回不同类型的数据interface User { id: number; name: string; } interface Product { id: number; price: number; } function fetchData(endpoint: users): PromiseUser[]; function fetchData(endpoint: products): PromiseProduct[]; function fetchData(endpoint: string): Promiseany { return axios.get(/api/${endpoint}).then(res res.data); }这样封装后调用fetchData(users)时TypeScript会自动知道返回值是User[]类型大大提升了代码的可维护性。4. 高级技巧与常见问题4.1 联合类型与重载的选择很多新手会困惑什么时候该用联合类型什么时候该用函数重载我的经验法则是如果不同参数类型对应完全不同的业务逻辑用重载如果只是参数类型不同但处理逻辑相似用联合类型比如下面这个例子就更适合用联合类型function formatValue(value: string | number): string { return String(value).toUpperCase(); }4.2 重载顺序的重要性重载签名的顺序非常关键TypeScript会按顺序匹配重载所以更具体的签名应该放在前面// 正确顺序 function process(value: Date): string; function process(value: string | number): string; // 错误顺序Date也是对象会被第二个签名捕获 function process(value: object): string; function process(value: Date): string;我曾经因为顺序问题调试了半天最后发现是签名顺序写反了导致永远匹配不到正确的重载。4.3 可选参数与重载处理可选参数时重载通常比直接在参数上加?更清晰// 不推荐 function createElement(tag: string, attributes?: object, children?: any[]): HTMLElement; // 推荐 function createElement(tag: string): HTMLElement; function createElement(tag: string, attributes: object): HTMLElement; function createElement(tag: string, attributes: object, children: any[]): HTMLElement;后者能更精确地描述每种调用方式对应的返回类型。5. 实战案例构建一个灵活的查询构建器让我们用一个完整的例子来综合运用前面学到的知识。假设我们要构建一个查询构建器支持多种查询方式interface Query { where: Recordstring, any; limit?: number; orderBy?: string; } // 情况1通过ID查询 function buildQuery(id: number): Query; // 情况2通过条件对象查询 function buildQuery(conditions: Recordstring, any): Query; // 情况3完整参数查询 function buildQuery(conditions: Recordstring, any, limit: number, orderBy: string): Query; function buildQuery( arg1: number | Recordstring, any, arg2?: number, arg3?: string ): Query { if (typeof arg1 number) { return { where: { id: arg1 } }; } const query: Query { where: arg1 }; if (arg2 ! undefined) { query.limit arg2; } if (arg3 ! undefined) { query.orderBy arg3; } return query; }这个例子展示了如何处理不同类型的第一个参数处理可选参数返回统一类型但结构不同的结果在实际项目中这种模式特别适合构建配置对象或API参数。